From c214ac578c70794d80a1cb74a2fe0cc418c6a9ad Mon Sep 17 00:00:00 2001 From: vsadov Date: Wed, 4 Sep 2019 14:42:38 -0700 Subject: [PATCH] In a rare case when local queue has multiple segments, do a local Dequeue to ensure that continuously nonempty global queue does not delay retirement of old segments. This is not a very common scenario, generally happening only at start up, but mitigation is also simple. --- .../shared/System/Threading/ThreadPool.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs index fa5541eacf78..8f11afec1843 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs @@ -1336,6 +1336,18 @@ internal bool TryRemove(object callback) public object? DequeueAny(ref bool missedSteal, LocalQueue localQueue) { + // We come here after Pop failed. + // We look at the global queue and then do a sweep through all local queues for any work remaining. + // + // However, in a rare case when local queue has multiple segments, do a local Dequeue first + // to ensure that continuously nonempty global queue does not delay retirement of old segments. + if (localQueue._enqSegment != localQueue._deqSegment) + { + object? locallyDequeued = localQueue.Dequeue(ref missedSteal); + if (locallyDequeued != null) + return locallyDequeued; + } + object? callback = _globalQueue.Dequeue(localQueue); if (callback == null) {