@@ -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