Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the current task scheduler flow into ThreadPool.QueueUserWorkItem callbacks?

Does the current task scheduler flow into ThreadPool.QueueUserWorkItem callbacks, as a part of the execution context flow?

I expect it would not, so the following debug asserts should be passing. I couldn't find any confirmation of that online.

var scheduler = new CustomTaskScheduler();
await Task.Factory.StartNew(async () =>
{
    Debug.Assert(TaskScheduler.Current == scheduler);

    var tcs = new TaskCompletionSource<bool>();
    ThreadPool.QueueUserWorkItem(_ =>
    {
        Debug.Assert(TaskScheduler.Current != scheduler);
        Debug.Assert(TaskScheduler.Current == TaskScheduler.Default);
        tcs.SetResult(true);
    });

    await tcs.Task;
    Debug.Assert(TaskScheduler.Current == scheduler);
},
CancellationToken.None,
TaskCreationOptions.None,
scheduler).Unwrap();

like image 480
noseratio Avatar asked Oct 24 '25 18:10

noseratio


1 Answers

Does the current task scheduler flow into ThreadPool.QueueUserWorkItem callbacks, as a part of the execution context flow?

To my future self: no, it doesn't, as expected. Here's a simple CustomTaskScheduler to test the code in question:

public class CustomTaskScheduler : TaskScheduler
{
    protected override IEnumerable<Task>? GetScheduledTasks()
    {
        throw new NotImplementedException();
    }

    protected override void QueueTask(Task task)
    {
        ThreadPool.QueueUserWorkItem(t =>
            base.TryExecuteTask((Task)t!), task);
    }

    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        return false;
    }
}

Inside the ThreadPool.QueueUserWorkItem callback, the current task scheduler is indeed set back to TaskScheduler.Default:

var scheduler = new CustomTaskScheduler();
await Task.Factory.StartNew(async () =>
{
    Debug.Assert(TaskScheduler.Current == scheduler);

    var tcs = new TaskCompletionSource<bool>();
    ThreadPool.QueueUserWorkItem(_ =>
    {
        Debug.Assert(TaskScheduler.Current != scheduler);
        Debug.Assert(TaskScheduler.Current == TaskScheduler.Default);
        tcs.SetResult(true);
    });

    await tcs.Task;
    Debug.Assert(TaskScheduler.Current == scheduler);
},
CancellationToken.None,
TaskCreationOptions.None,
scheduler).Unwrap();

like image 199
noseratio Avatar answered Oct 26 '25 06:10

noseratio