MishaU
MishaU

Reputation: 708

Execution context for code after await inside Task

Maybe I misunderstood something, but I always think that by default, when an incomplete Task is awaited, the current “context” is captured and used to resume the method when the Task completes. But I found quite strange behavior (at least for me) where this is wrong:

private static Task StartTask()
{
    return Task.Run(() =>
        {
            Debug.WriteLine("StartTask thread id = " + Thread.CurrentThread.ManagedThreadId);
        });
}

private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    await Task.Run(async () =>
        {
            Debug.WriteLine("Thread id before await task = " + Thread.CurrentThread.ManagedThreadId);
            await StartTask().ConfigureAwait(true);
            Debug.WriteLine("Thread id after await task = " + Thread.CurrentThread.ManagedThreadId);
        });
}

and I receive such result in debug output

Thread id before await task = 12
StartTask thread id = 13
Thread id after await task = 13

Why did code execution context change after await?

Upvotes: 3

Views: 2143

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 457207

by default, when an incomplete Task is awaited, the current “context” is captured and used to resume the method when the Task completes

That's correct. The behavior you observed is correct.

The question is: what is the "context" that is captured? It is the current SynchronizationContext, unless it is null, in which case it is the current TaskScheduler.

When Task.Run executes your delegate, it is executing it on the thread pool. Thus, there is no current SynchronizationContext. So the current TaskScheduler is used; note that since there is not actually a task executing (the delegate is executed directly on the thread pool), the current TaskScheduler is the default TaskScheduler, which represents the thread pool.

Upvotes: 4

Related Questions