2

我目前正在深入阅读 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);
    }

感谢您

4

1 回答 1

6

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

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

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

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

于 2013-10-31T13:23:01.570 回答