繁体   English   中英

为什么这个异步方法不会导致线程死锁?

[英]Why this async method don't cause deadlock on a thread?

我需要解释为什么这段代码不会导致它正在运行的线程死锁(这是一个 WinForm 应用程序,这些发生在 button_Click 中):

Task FakeMainThread = Task.Run(async() =>  // fake main thread
{
    async Task asyncMethod()               // executed in FakeMainThread
    {
        await Task.Run(() =>               // 'await'ing in FakeMainThread
        {
            Thread.Sleep(5000);
            MessageBox.Show("child Task finished");
            return 3;
        });
        MessageBox.Show("asyncMethod finished");
    }

    asyncMethod().Wait();     // deadlock should appear in FakeMainThread 
    MessageBox.Show("FakeMainThread finished");
    return 4;
});

asyncMethod().Wait(); 应该阻止 fakeMainThread 任务的线程,而它正在等待另一个任务完成,并且由于在await中也发生了等待,它不应该能够“等待”并且死锁应该出现在 fakeMainThread 上。 但它没有发生,我看到 bot MessageBox.Show("asyncMethod finished"); MessageBox.Show("FakeMainThread finished"); 消息。 注意:如果我把这个:

async Task asyncMethod()               
{
    await Task.Run(() =>              
    {
        Thread.Sleep(5000);
        MessageBox.Show("child Task finished");
        return 3;
    });

    MessageBox.Show("asyncMethod finished");
}

asyncMethod().Wait();          // deadlock appears in Main Thread (UI)
MessageBox.Show("FakeMainThread finished");

在 directli 内的 main button1_click() 中,UI 上出现死锁。 谢谢!

由于SynchronizationContext ,您不会在第一个代码示例中遇到死锁。 这个上下文说明了 await 必须做什么来恢复你的代码。 当您开始一项新任务 ( Task.Run ) 时,您将获得默认上下文。 button1_click中,您可以从表单中获取上下文。

表单的上下文只允许执行一个线程(用于绘制/更新表单的线程)。

当您调用.Wait()时,您会保持该线程“锁定”并等待任务完成。 这意味着线程没有被释放用于另一项工作,这是表单进入“无响应”state 的原因之一。

当您执行await [code]并且该代码已完成时,它将要求同步上下文安排剩余的代码。

  • 在默认上下文的情况下,任何空闲线程都会被占用并且您的代码将继续,任务被标记为已完成,因此.Wait()中的“循环”收到信号表明任务已完成并继续。
  • 在 forms 上下文的情况下,只有一个线程,因此该任务的完成计划在当前代码完成后运行。 这就是僵局的原因。

避免这种死锁是您经常收到使用ConfigureAwait(false)的建议的主要原因,这告诉await它应该用默认的同步上下文替换当前的同步上下文,从而允许您使用任何空闲线程。 您不想使用此功能(或说ConfigureAwait(true) )的唯一原因是您是否需要更新表单(WPF 或 WinForms)上的某些内容,或者您需要 http 上下文(ASP.NET,而不是 ASP.NET 核心)。 这是因为只有一个线程可以访问您的表单或 http 上下文。 在这里,您的MessageBox.Show不会出现异常,因为这是 forms 上下文的“外部”,并且不需要这个特殊的线程/同步上下文。

有关详细信息,请参阅https://devblogs.microsoft.com/dotnet/configureawait-faq/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM