GUI task.wait与Console或ThreadPool的死锁

时间:2013-10-31 13:20:55

标签: c# task

我目前正在深入阅读C#(第3版),其中一个警告是使用带有task.wait的GUI线程是危险的,因为它可能导致死锁。但它不是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);
    }

谢谢你

1 个答案:

答案 0 :(得分:5)

我详细解释了这一点in a blog post

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

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

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