private void ThreadBasedDispatchLoop()
{
_taskProcessingThread.Value = true;
try
{
// If the scheduler is disposed, the cancellation token will be set and
// we'll receive an OperationCanceledException. That OCE should not crash the process.
try
{
// If a thread abort occurs, we'll try to reset it and continue running.
while (true)
{
try
{
// For each task queued to the scheduler, try to execute it.
foreach (var task in _blockingTaskQueue.GetConsumingEnumerable(_disposeCancellation.Token))
{
Interlocked.Increment(ref _pendingTasks);
task.ContinueWith(t => { Interlocked.Decrement(ref _pendingTasks); });
try
{
TryExecuteTask(task);
}
catch { Interlocked.Decrement(ref _pendingTasks); }
}
}
catch (ThreadAbortException)
{
// If we received a thread abort, and that thread abort was due to shutting down
// or unloading, let it pass through. Otherwise, reset the abort so we can
// continue processing work items.
if (!Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload())
{
Thread.ResetAbort();
}
}
}
}
catch (OperationCanceledException) { }
}
finally
{
// Run a cleanup routine if there was one
_taskProcessingThread.Value = false;
}
}