Skip to content

Commit 0fde84e

Browse files
committed
ordering issue in work queue
1 parent 2d127d0 commit 0fde84e

1 file changed

Lines changed: 19 additions & 11 deletions

File tree

src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,10 @@ public bool LocalFindAndPop(object obj)
366366
else
367367
{
368368
// Failed, restore head.
369-
m_headIndex = head;
369+
// This write must complete before we return with a missed steal and check if
370+
// there is a pending thread request because the thread that responds
371+
// to the request must see the write to not conclude that the queue is empty.
372+
Interlocked.Exchange(ref m_headIndex, head);
370373
}
371374
}
372375
}
@@ -839,14 +842,17 @@ public long GlobalCount
839842
// Dispatch (if YieldFromDispatchLoop is true), or performing periodic activities
840843
public const uint DispatchQuantumMs = 30;
841844

845+
public enum DispatchResult
846+
{
847+
Spurious = 0, // the thread was invited, but there was no work in the queue.
848+
Regular = 1, // this thread did as much work as was available or its quantum expired.
849+
ShouldStop = 2, // this thread stopped working early.
850+
}
851+
842852
/// <summary>
843853
/// Dispatches work items to this thread.
844854
/// </summary>
845-
/// <returns>
846-
/// <c>true</c> if this thread did as much work as was available or its quantum expired.
847-
/// <c>false</c> if this thread stopped working early.
848-
/// </returns>
849-
internal static bool Dispatch()
855+
internal static DispatchResult Dispatch()
850856
{
851857
ThreadPoolWorkQueue workQueue = ThreadPool.s_workQueue;
852858
ThreadPoolWorkQueueThreadLocals tl = workQueue.GetOrCreateThreadLocals();
@@ -862,10 +868,11 @@ internal static bool Dispatch()
862868
ThreadPool.EnsureWorkerRequested();
863869
}
864870

865-
// Tell the VM we're returning normally, not because Hill Climbing asked us to return.
866-
return true;
871+
// The thread found no work.
872+
return DispatchResult.Spurious;
867873
}
868874

875+
869876
// The workitems that are currently in the queues could have asked only for one worker.
870877
// We are going to process a workitem, which may take unknown time or even block.
871878
// In a worst case the current workitem will indirectly depend on progress of other
@@ -921,7 +928,7 @@ internal static bool Dispatch()
921928
ThreadPool.EnsureWorkerRequested();
922929
}
923930

924-
return true;
931+
return DispatchResult.Regular;
925932
}
926933
}
927934

@@ -977,7 +984,8 @@ internal static bool Dispatch()
977984
{
978985
workQueue.UnassignWorkItemQueue(tl);
979986
}
980-
return false;
987+
988+
return DispatchResult.ShouldStop;
981989
}
982990

983991
// Check if the dispatch quantum has expired
@@ -997,7 +1005,7 @@ internal static bool Dispatch()
9971005
{
9981006
workQueue.UnassignWorkItemQueue(tl);
9991007
}
1000-
return true;
1008+
return DispatchResult.Regular;
10011009
}
10021010

10031011
if (s_assignableWorkItemQueueCount > 0)

0 commit comments

Comments
 (0)