Does Task.ContinueWith capture the calling thread

2019-02-12 10:08发布

问题:

The Test_Click below is a simplified version of code which runs on a UI thread (with WindowsFormsSynchronizationContext):

void Test_Click(object sender, EventArgs e)
{
    var task = DoNavigationAsync();
    task.ContinueWith((t) =>
    {
        MessageBox.Show("Navigation done!");
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

Should I explicitly specify TaskScheduler.FromCurrentSynchronizationContext() to make sure the continuation action will be executed on the same UI thread? Or does ContinueWith capture the execution context automatically (thus, making TaskScheduler argument redundant in this case)?

I assume it doesn't do it by default (unlike await), but so far I could not find an online resource to confirm this.

回答1:

It doesn't use the current synchronization context by default, but TaskScheduler.Current, as seen in the following decompiled code:

public Task ContinueWith(Action<Task<TResult>> continuationAction)
{
  StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  return this.ContinueWith(continuationAction, TaskScheduler.Current, new CancellationToken(), TaskContinuationOptions.None, ref stackMark);
}

TaskScheduler.Current is either TaskScheduler.Default or the TaskScheduler of the current task if the task is a child task. Always specify the task scheduler if you don't want to run into weird problems, or better, use await if you can.