Home

Linqpad runs continuations on the same thread most of the time with TaskScheduler.Default

edited June 23

Running this code on LinqPad 8.3 x64, .NET 6 runtime, .NET 7 host will almost always output the same threadId number

void Main() {

    TaskFactory tf = new TaskFactory(CancellationToken.None,
    TaskCreationOptions.RunContinuationsAsynchronously,
    TaskContinuationOptions.None, // Default supposed to be Asynchronous
    TaskScheduler.Default);

    tf.StartNew(() => {
        Thread.Sleep(1000);
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    }).ContinueWith(t => {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    }, TaskScheduler.Default);

    Thread.Sleep(2000);
}

Running this as a separate console application with VS2019 always outputs different thread IDs.

Are there some LinqPad specifics that make the Task.Scheduler.Default (supposed to be the thread pool task schedler) schedule on the same thread?

The same happens even if we really wanted to force the issue like this

   tf.StartNew(() => {
        Thread.Sleep(1000);
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    }).ContinueWith(t => {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    }, CancellationToken.None,
    TaskContinuationOptions.RunContinuationsAsynchronously,
    TaskScheduler.Default);

same with Task.Run

  Task.Run(() => Console.WriteLine(Thread.CurrentThread.ManagedThreadId))
    .ContinueWith(t => {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(1000);
        }
        ,
    TaskContinuationOptions.RunContinuationsAsynchronously);

    Thread.Sleep(2000);

Comments

  • LINQPad doesn't do anything to mess with the task scheduler.

    As I understand, the asynchronous continuation option determines behavior. It makes no guarantees about which thread the continuation will run on - that is an implementation detail. The TPL can still provide asynchronous behavior while re-using the same underlying thread. I suspect what's happening in your case is that the thread used for the first task is returned to the threadpool fast enough to be re-used for the next scheduled task. Whether or not this occurs is down to a race; therefore the output of this program is indeterminate.

Sign In or Register to comment.