@@ -389,6 +389,7 @@ public int Count
389
389
}
390
390
391
391
internal bool loggingEnabled ;
392
+ private bool _dispatchTimeSensitiveWorkFirst ;
392
393
internal readonly ConcurrentQueue < object > workItems = new ConcurrentQueue < object > ( ) ; // SOS's ThreadPool command depends on this name
393
394
internal readonly ConcurrentQueue < IThreadPoolWorkItem > ? timeSensitiveWorkQueue =
394
395
ThreadPool . SupportsTimeSensitiveWorkItems ? new ConcurrentQueue < IThreadPoolWorkItem > ( ) : null ;
@@ -594,27 +595,46 @@ internal static bool Dispatch()
594
595
// Before dequeuing the first work item, acknowledge that the thread request has been satisfied
595
596
workQueue . MarkThreadRequestSatisfied ( ) ;
596
597
597
- object ? workItem ;
598
+ object ? workItem = null ;
598
599
{
599
- bool missedSteal = false ;
600
- workItem = workQueue . Dequeue ( tl , ref missedSteal ) ;
600
+ #pragma warning disable CS0162 // Unreachable code detected. SupportsTimeSensitiveWorkItems may be a constant in some runtimes.
601
+ if ( ThreadPool . SupportsTimeSensitiveWorkItems )
602
+ {
603
+ // Alternate between checking for time-sensitive work or other work first, that way both sets of work items
604
+ // get a chance to run in situations where worker threads are starved and work items that run also take over
605
+ // the thread, sustaining starvation. For example, if time-sensitive work is always checked last here, timer
606
+ // callbacks may not run when worker threads are continually starved.
607
+ bool dispatchTimeSensitiveWorkFirst = workQueue . _dispatchTimeSensitiveWorkFirst ;
608
+ workQueue . _dispatchTimeSensitiveWorkFirst = ! dispatchTimeSensitiveWorkFirst ;
609
+ if ( dispatchTimeSensitiveWorkFirst )
610
+ {
611
+ workItem = workQueue . TryDequeueTimeSensitiveWorkItem ( ) ;
612
+ }
613
+ }
614
+ #pragma warning restore CS0162
601
615
602
616
if ( workItem == null )
603
617
{
604
- //
605
- // No work.
606
- // If we missed a steal, though, there may be more work in the queue.
607
- // Instead of looping around and trying again, we'll just request another thread. Hopefully the thread
608
- // that owns the contended work-stealing queue will pick up its own workitems in the meantime,
609
- // which will be more efficient than this thread doing it anyway.
610
- //
611
- if ( missedSteal )
618
+ bool missedSteal = false ;
619
+ workItem = workQueue . Dequeue ( tl , ref missedSteal ) ;
620
+
621
+ if ( workItem == null )
612
622
{
613
- workQueue . EnsureThreadRequested ( ) ;
614
- }
623
+ //
624
+ // No work.
625
+ // If we missed a steal, though, there may be more work in the queue.
626
+ // Instead of looping around and trying again, we'll just request another thread. Hopefully the thread
627
+ // that owns the contended work-stealing queue will pick up its own workitems in the meantime,
628
+ // which will be more efficient than this thread doing it anyway.
629
+ //
630
+ if ( missedSteal )
631
+ {
632
+ workQueue . EnsureThreadRequested ( ) ;
633
+ }
615
634
616
- // Tell the VM we're returning normally, not because Hill Climbing asked us to return.
617
- return true ;
635
+ // Tell the VM we're returning normally, not because Hill Climbing asked us to return.
636
+ return true ;
637
+ }
618
638
}
619
639
620
640
// A work item was successfully dequeued, and there may be more work items to process. Request a thread to
0 commit comments