Skip to content

Commit 2a6b71c

Browse files
committed
ShouldStop means no spin.
1 parent 13111ee commit 2a6b71c

1 file changed

Lines changed: 18 additions & 12 deletions

File tree

src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,14 @@ private static void WorkerThreadStart()
105105

106106
while (true)
107107
{
108-
bool spuriousRequest = false;
108+
bool noSpin = false;
109109
while (true)
110110
{
111-
bool signaled = spuriousRequest ? semaphore.WaitNoSpin(timeoutMs) : semaphore.Wait(timeoutMs);
111+
bool signaled = noSpin ? semaphore.WaitNoSpin(timeoutMs) : semaphore.Wait(timeoutMs);
112112
if (!signaled)
113113
break;
114114

115-
WorkerDoWork(threadPoolInstance, out spuriousRequest);
115+
WorkerDoWork(threadPoolInstance, out noSpin);
116116
}
117117

118118
// We've timed out waiting on the semaphore. Time to exit.
@@ -124,13 +124,13 @@ private static void WorkerThreadStart()
124124
}
125125
}
126126

127-
private static void WorkerDoWork(PortableThreadPool threadPoolInstance, out bool spuriousRequest)
127+
private static void WorkerDoWork(PortableThreadPool threadPoolInstance, out bool noSpin)
128128
{
129129
do
130130
{
131-
// We generally avoid spurious wakes as they are wasteful, so we nearly always should see a request.
132-
// However, we allow external wakes when thread goals change, which can result in "stolen" requests,
133-
// thus sometimes there is no active request and we need to check.
131+
// We generally avoid spurious wakes by requesting one thread at a time. We nearly always should see a request.
132+
// However, we allow external wakes when thread goals change, which can result in "stolen" requests.
133+
// Therefore we check for request before clearing it and dispatching workitems.
134134
if (threadPoolInstance._separated._hasOutstandingThreadRequest != 0 &&
135135
Interlocked.Exchange(ref threadPoolInstance._separated._hasOutstandingThreadRequest, 0) != 0)
136136
{
@@ -139,22 +139,28 @@ private static void WorkerDoWork(PortableThreadPool threadPoolInstance, out bool
139139
switch (ThreadPoolWorkQueue.Dispatch())
140140
{
141141
case ThreadPoolWorkQueue.DispatchResult.Spurious:
142-
spuriousRequest = true;
142+
// We were invited but found no work. This is counterproductive. We should park.
143+
noSpin = true;
143144
break;
144145

145146
case ThreadPoolWorkQueue.DispatchResult.ShouldStop:
146-
spuriousRequest = false;
147-
// We are above goal and this worker is already removed in the counts.
147+
// We are above goal and this worker is already removed in the counts.
148+
// Chances to be invited back right away are low, so just park.
149+
noSpin = true;
148150
return;
149151

150152
default:
151-
spuriousRequest = false;
153+
// We did some work, but then there was nothing to do.
154+
// Spin a bit before parking in case we are invited back.
155+
noSpin = false;
152156
break;
153157
}
154158
}
155159
else
156160
{
157-
spuriousRequest = true;
161+
// Not a common case. This can happen when worker goal was increased and invited extra threads.
162+
// We will spin in case there is work for all and another request will soon follow.
163+
noSpin = false;
158164
}
159165

160166
// We could not find more work in the queue and will try to stop being active.

0 commit comments

Comments
 (0)