Ton*_*ony 4 c# deadlock task async-await
我阅读了 Task.Run 和 Task.Factory.StartNew 的差异。
Task.Run(() => {});
Run Code Online (Sandbox Code Playgroud)
应该相当于
Task.Factory.StartNew(() => {}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
Run Code Online (Sandbox Code Playgroud)
但是在我的代码中,我希望由于 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);
}
Run Code Online (Sandbox Code Playgroud)
但这并不是死锁。DoSomethingAsync 中的异常被抛出但从未被捕获。在 Task.Delay 之后等待 Task 也不会抛出,因为它是 RanToCompletion。
使用 Task.Run 时,它按预期死锁:
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);
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释这种行为吗?
Task.Factory.StartNew与异步委托一起使用时的方法返回嵌套任务:Task<Task>。您将此嵌套任务分配给类型为 的变量Task,这是允许的,因为该类是Task<TResult>从该类派生的Task。然后发生的事情是您失去了对内部任务的引用,因此您无法等待它。当您await this.backgroundTask在等待外部Task<Task>,但无法获得等待操作的结果时,即 a Task、内部Task和awaitit。内在的任务已经变成了即发即忘的任务。