I tried to find an answer for this but couldn\'t. What I was wondering is that on which thread Task.ContinueWith
delegate is called.
For await I know that it tr
This depends on the scheduler that is associated with the continuation. By default, task continuations are scheduled through the Current scheduler, being the TaskScheduler
associated with the currently executing task. When ContinueWith
is not called from within a task, Current
will return the Default scheduler, which is the default TaskScheduler
instance provided by the .NET Framework, and which will schedule your tasks on the thread pool.
If you want to influence this behaviour, you can call one of the ContinueWith
overloads that takes a TaskScheduler
parameter. A common pattern is to pass TaskScheduler.FromCurrentSynchronizationContext()
when creating continuations on the UI thread, as this would cause the continuation to be dispatched back onto the UI thread when executed.
Edit: In reply to your comment: The deadlock may arise if you spawn a child task (intended to run on the thread pool) from a continuation running on the UI thread. In such cases, the child task will inherit the task scheduler from the parent task, which would be bound to the UI thread, causing the child task to run on the UI thread too.
Task.Factory.StartNew(() =>
{
// Do background work.
}).ContinueWith(_ =>
{
// Update UI, then spawn child task to do more background work...
Task.Factory.StartNew(() =>
{
// ...but child task runs on UI thread!
});
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
To resolve this, you can use the StartNew
overload that accepts a TaskScheduler
parameter for the child task, and pass TaskScheduler.Default
to it:
// Update UI, then spawn child task to do more background work...
Task.Factory.StartNew(() =>
{
// ...and child task now runs on the thread pool.
},
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default);
Task.ContinueWith
is scheduled on the TaskScheduler.Current
unless specified otherwise by the parameters in one of the optional overloads.
If you don't have a custom scheduler in TaskScheduler.Current
(which is very likely) your continuation will run on the ThreadPool
.
Task.ContinueWith
never uses the SynchronizationContext
unless you create a TaskScheduler
out of it with TaskScheduler.FromCurrentSynchronizationContext
.
You can always state explicitly which TaskScheduler
is needed using one of the available overloads:
task.ContinueWith(
_ => {},
null,
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.Default); // Scheduled to the ThreadPool