Reputation: 593
I read about the differences of Task.Run and Task.Factory.StartNew.
Task.Run(() => {});
should be equivalent to
Task.Factory.StartNew(() => {}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
But in my code I expect a deadlock which is not happening because of Task.Factory.StartNew:
private Task backgroundTask;
private async Task DoSomethingAsync()
{
// this should deadlock
await this.backgroundTask.ConfigureAwait(false);
throw new Exception();
}
private async Task Test()
{
this.backgroundTask = Task.Factory.StartNew(async () =>
{
await this.DoSomethingAsync().ConfigureAwait(false);
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
// just wait here for testing/debugging
await Task.Delay(10000).ConfigureAwait(false);
// if no deadlock, this should throw
await this.backgroundTask.ConfigureAwait(false);
}
But it is not deadlocking. The exception in DoSomethingAsync is thrown but never catched. Awaiting the Task after the Task.Delay is not throwing either, because it is RanToCompletion.
When using Task.Run it is deadlocking as expected:
private Task backgroundTask;
private async Task DoSomethingAsync()
{
// this is deadlocking
await this.backgroundTask.ConfigureAwait(false);
throw new Exception();
}
private async Task Test()
{
this.backgroundTask= Task.Run(async () =>
{
await this.DoSomethingAsync().ConfigureAwait(false);
});
// just wait here for testing/debugging
await Task.Delay(10000).ConfigureAwait(false);
// never reached because of deadlock
await this.backgroundTask.ConfigureAwait(false);
}
Can anybody explain this behaviour?
Upvotes: 4
Views: 1310
Reputation: 43429
The method Task.Factory.StartNew
when used with an async delegate returns a nested task: Task<Task>
. You are assigning this nested task to a variable of type Task
, which is allowed because the class Task<TResult>
derives from the class Task
. What happens then is that you lose the reference to the inner task, so you have no way of awaiting it. When you await this.backgroundTask
you are awaiting the outer Task<Task>
, but you can't get the result of the await operation, which is a Task
, the inner Task
, and await
it. The inner task has become a fire-and-forget task.
Upvotes: 5