GUI task.wait 与 Console 或 ThreadPool 的死锁



我目前正在深入阅读C#(第3版),给出的警告之一是将GUI线程与task.wait一起使用是危险的,因为它可能导致死锁。但这不是ThreadPool或Console的问题。我的问题是为什么运行 task.wait 的线程没有死锁,因此对于以下代码(取自书本),即使是控制台应用程序(backround)线程也不会进入捕获,因为它会死锁。

public static void Main(string[] args = null)
{
        var source = new CancellationTokenSource();
        var task = TestInt(source.Token);
        source.CancelAfter(4000);
        Console.WriteLine("Status {0}",task.Status);
        try
        {
            task.Wait();
        }
        catch (AggregateException e)
        {
            Console.WriteLine("Caught {0}",e.InnerExceptions[0]);
        }
        Console.WriteLine("Final Status: {0}",task.Status);
        Console.ReadKey();
    }
    public static async Task TestInt(CancellationToken token, double start = 1)
    {
        await Task.Delay(TimeSpan.FromSeconds(30), token);
    }

谢谢

我在博客文章中详细解释了这一点。

发生的情况是(默认情况下)await将捕获当前"上下文"并使用该上下文恢复async方法的执行。这个"上下文"是SynchronizationContext.Current的,除非它是null的,在这种情况下它是TaskScheduler.Current的。

在您的示例中,SynchronizationContext.CurrentnullTaskScheduler.CurrentTaskScheduler.Default,即线程池任务调度程序。因此,async方法在线程池线程上恢复,并且没有死锁。线程池线程完成 async 方法,完成Task,允许主线程完成其等待。

(在死锁情况下,有一个表示 UI 线程的SynchronizationContext,因此 async 方法尝试在 UI 线程上恢复,但 UI 线程被调用 Wait 阻止)。

最新更新