GUI task.wait与Console或ThreadPool的死锁

Ale*_*pka 2 c# task

我目前正在深入阅读C#(第3版),其中一个警告是使用带有task.wait的GUI线程是危险的,因为它可能导致死锁.但它不是ThreadPool或Console的问题.我的问题是为什么运行task.wait的线程没有死锁,所以对于下面的代码(取自书),即使控制台应用程序(后台)线程也不会使它成为陷阱,因为它会死锁.

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);
    }
Run Code Online (Sandbox Code Playgroud)

谢谢

Ste*_*ary 6

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

会发生什么(默认情况下)await将捕获当前的"上下文"并使用该上下文来恢复该async方法的执行.这种"背景" SynchronizationContext.Current除非是null,否则就是这样TaskScheduler.Current.

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

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