@@ -396,10 +396,17 @@ void WorkStealingThreadPool::WorkStealingThreadPoolImpl::Lifeguard::
396
396
// reduce the check rate if the pool is idle.
397
397
if (pool_->IsShutdown ()) {
398
398
if (pool_->IsQuiesced ()) break ;
399
- } else {
400
- lifeguard_should_shut_down_->WaitForNotificationWithTimeout (
401
- absl::Milliseconds (backoff_.NextAttemptDelay ().millis ()));
399
+ if (MaybeStartNewThread ()) {
400
+ // A new thread needed to be spawned to handle the workload.
401
+ // Wait just a small while before checking again to prevent a busy loop.
402
+ backoff_.Reset ();
403
+ }
404
+ // Sleep for a bit.
405
+ pool_->work_signal ()->WaitWithTimeout (backoff_.NextAttemptDelay ());
406
+ continue ;
402
407
}
408
+ lifeguard_should_shut_down_->WaitForNotificationWithTimeout (
409
+ absl::Milliseconds (backoff_.NextAttemptDelay ().millis ()));
403
410
MaybeStartNewThread ();
404
411
}
405
412
lifeguard_running_.store (false , std::memory_order_relaxed);
@@ -423,11 +430,11 @@ WorkStealingThreadPool::WorkStealingThreadPoolImpl::Lifeguard::~Lifeguard() {
423
430
lifeguard_is_shut_down_ = std::make_unique<grpc_core::Notification>();
424
431
}
425
432
426
- void WorkStealingThreadPool::WorkStealingThreadPoolImpl::Lifeguard::
433
+ bool WorkStealingThreadPool::WorkStealingThreadPoolImpl::Lifeguard::
427
434
MaybeStartNewThread () {
428
435
// No new threads are started when forking.
429
436
// No new work is done when forking needs to begin.
430
- if (pool_->forking_ .load ()) return ;
437
+ if (pool_->forking_ .load ()) return false ;
431
438
const auto living_thread_count = pool_->living_thread_count ()->count ();
432
439
// Wake an idle worker thread if there's global work to be had.
433
440
if (pool_->busy_thread_count ()->count () < living_thread_count) {
@@ -436,7 +443,7 @@ void WorkStealingThreadPool::WorkStealingThreadPoolImpl::Lifeguard::
436
443
backoff_.Reset ();
437
444
}
438
445
// Idle threads will eventually wake up for an attempt at work stealing.
439
- return ;
446
+ return false ;
440
447
}
441
448
// No new threads if in the throttled state.
442
449
// However, all workers are busy, so the Lifeguard should be more
@@ -446,7 +453,7 @@ void WorkStealingThreadPool::WorkStealingThreadPoolImpl::Lifeguard::
446
453
pool_->last_started_thread_ ) <
447
454
kTimeBetweenThrottledThreadStarts ) {
448
455
backoff_.Reset ();
449
- return ;
456
+ return false ;
450
457
}
451
458
// All workers are busy and the pool is not throttled. Start a new thread.
452
459
// TODO(hork): new threads may spawn when there is no work in the global
@@ -458,6 +465,7 @@ void WorkStealingThreadPool::WorkStealingThreadPoolImpl::Lifeguard::
458
465
pool_->StartThread ();
459
466
// Tell the lifeguard to monitor the pool more closely.
460
467
backoff_.Reset ();
468
+ return true ;
461
469
}
462
470
463
471
// -------- WorkStealingThreadPool::ThreadState --------
0 commit comments