thread_pool: extract _try_claim_removal to deduplicate CAS loop

_process_func contained two identical compare_exchange_weak loops for
claiming a _remove_count decrement — one in the poison-pill handler
and one after task completion.  Duplicating the loop risks the two
copies diverging during future edits and makes the function harder
to follow.

Extract the loop into _try_claim_removal() which returns true when a
decrement is successfully claimed.  Both call sites now delegate to
the shared helper.  The relaxed memory ordering rationale (the
subsequent _remove_self acquires _threads_mutex, providing the
happens-before with the scaling-side increment) is documented on the
helper.  No functional change.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Antonio S. Musumeci
2026-04-10 18:46:48 -04:00
co-authored by Claude Opus 4.6
parent 2d3528431b
commit 7ce5364c35
+28 -30
View File
@@ -94,6 +94,7 @@ private:
int _remove_thread_scaling_locked();
void _remove_self(pthread_t t_);
bool _try_remove_self_if_above(pthread_t t_, std::size_t min_count_);
bool _try_claim_removal();
void _maybe_grow_on_pressure();
static std::uint64_t _now_usecs();
@@ -391,18 +392,11 @@ ThreadPool::_process_func(Func &func_)
// this pill is ours — detach and exit. If the count is zero,
// a worker already claimed the decrement via the task-
// completion path below; this pill is stale — keep working.
{
std::size_t count = _remove_count.load(std::memory_order_relaxed);
while(count > 0)
{
if(_remove_count.compare_exchange_weak(count,count - 1,
std::memory_order_relaxed))
{
_remove_self(pthread_self());
return EXIT;
}
}
}
if(_try_claim_removal())
{
_remove_self(pthread_self());
return EXIT;
}
return CONTINUE;
}
@@ -434,24 +428,11 @@ ThreadPool::_process_func(Func &func_)
// Workers race to claim a decrement after each task; the winner
// detaches itself and exits. During shutdown (_stop set),
// _remove_self is a no-op, so the destructor still joins us.
//
// Relaxed ordering is sufficient here: the only side-effect of
// claiming the decrement is _remove_self, which acquires
// _threads_mutex. That mutex provides the necessary happens-
// before relationship between the increment (scaling side) and
// the erase/detach (worker side).
{
std::size_t count = _remove_count.load(std::memory_order_relaxed);
while(count > 0)
{
if(_remove_count.compare_exchange_weak(count,count - 1,
std::memory_order_relaxed))
{
_remove_self(pthread_self());
return EXIT;
}
}
}
if(_try_claim_removal())
{
_remove_self(pthread_self());
return EXIT;
}
return CONTINUE;
}
@@ -708,6 +689,23 @@ ThreadPool::monitor_routine(void *arg_)
}
// Try to claim one pending removal. Returns true if a _remove_count
// decrement was successfully claimed, false if the count was zero.
inline
bool
ThreadPool::_try_claim_removal()
{
std::size_t count = _remove_count.load(std::memory_order_relaxed);
while(count > 0)
{
if(_remove_count.compare_exchange_weak(count,count - 1,
std::memory_order_relaxed))
return true;
}
return false;
}
inline
void
ThreadPool::_remove_self(pthread_t t_)