Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么这个异步方法不';不会导致线程死锁吗?_C#_Async Await_Task_Deadlock - Fatal编程技术网

C# 为什么这个异步方法不';不会导致线程死锁吗?

C# 为什么这个异步方法不';不会导致线程死锁吗?,c#,async-await,task,deadlock,C#,Async Await,Task,Deadlock,我需要一个解释,为什么这段代码不会在它运行的线程上造成死锁 (这是一个WinForm应用程序,在单击按钮时发生): asyncMethod().Wait()应该在等待另一个任务完成时阻止fakeMainThread任务的线程,并且由于在fakeMainThread中也发生了等待,因此它不应该能够“等待”,并且fakeMainThread上应该出现死锁。但这并没有发生,我看到botMessageBox.Show(“AsyncMethodFinished”)和MessageBox.Show(“Fak

我需要一个解释,为什么这段代码不会在它运行的线程上造成死锁 (这是一个WinForm应用程序,在单击按钮时发生):

asyncMethod().Wait()
应该在等待另一个任务完成时阻止fakeMainThread任务的线程,并且由于在fakeMainThread中也发生了
等待
,因此它不应该能够“等待”,并且fakeMainThread上应该出现死锁。但这并没有发生,我看到bot
MessageBox.Show(“AsyncMethodFinished”)
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");

在主按钮中,UI上显示directli死锁的内部。谢谢

在第一个代码示例中,由于
SynchronizationContext
,您不会遇到死锁。此上下文说明了await必须执行哪些操作才能恢复代码。启动新任务(
task.Run
)时,将获得默认上下文。在
按钮1中,单击
可从表单中获取上下文

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

当您调用
.Wait()
时,您将保持线程“锁定”,等待任务完成。这意味着线程不会被释放用于另一个作业,这也是表单进入“未响应”状态的原因之一

当您执行一个
等待[code]
,并且该代码已完成时,它将要求同步上下文安排代码的其余部分

  • 在默认上下文中,任何空闲线程都被占用,代码将继续,任务标记为已完成,因此
    .Wait()
    中的“循环”将收到任务已完成并继续的信号
  • 对于表单上下文,只有一个线程,因此此任务的完成计划在当前代码完成后运行。这就是僵局的原因
避免此死锁是您经常收到使用
ConfigureAwait(false)
的建议的主要原因,这告诉
await
它应该用默认的同步上下文替换当前的同步上下文,从而允许您使用任何空闲线程。 您不想使用此选项(或者说
ConfigureAwait(true)
)的唯一原因是您需要更新表单上的某些内容(WPF或WinForms),或者您需要http上下文(ASP.NET,而不是ASP.NET核心)。这是因为只有一个线程可以访问表单或http上下文。在这里,您的
消息框上不会出现异常。Show
,因为这是表单上下文的“外部”,不需要这个特殊的线程/同步上下文


有关更多信息,请参阅。

由于同步上下文的原因,您在第一个代码示例中没有遇到死锁。此上下文说明了await必须执行哪些操作才能恢复代码。启动新任务(
task.Run
)时,将获得默认上下文。在
按钮1中,单击
可从表单中获取上下文

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

当您调用
.Wait()
时,您将保持线程“锁定”,等待任务完成。这意味着线程不会被释放用于另一个作业,这也是表单进入“未响应”状态的原因之一

当您执行一个
等待[code]
,并且该代码已完成时,它将要求同步上下文安排代码的其余部分

  • 在默认上下文中,任何空闲线程都被占用,代码将继续,任务标记为已完成,因此
    .Wait()
    中的“循环”将收到任务已完成并继续的信号
  • 对于表单上下文,只有一个线程,因此此任务的完成计划在当前代码完成后运行。这就是僵局的原因
避免此死锁是您经常收到使用
ConfigureAwait(false)
的建议的主要原因,这告诉
await
它应该用默认的同步上下文替换当前的同步上下文,从而允许您使用任何空闲线程。 您不想使用此选项(或者说
ConfigureAwait(true)
)的唯一原因是您需要更新表单上的某些内容(WPF或WinForms),或者您需要http上下文(ASP.NET,而不是ASP.NET核心)。这是因为只有一个线程可以访问表单或http上下文。在这里,您的
消息框上不会出现异常。Show
,因为这是表单上下文的“外部”,不需要这个特殊的线程/同步上下文


有关更多信息,请参阅。

为什么不“等待”的线程池线程(它只是在调用
Wait()
)死锁?它没有触及UI线程(通过同步上下文),因此您没有阻止它-为什么它会在意?为什么不“等待”的线程池线程应该等待(它只是调用
Wait()
)死锁?它没有触及UI线程(通过同步上下文),所以你没有阻止它-为什么它会在意?“当你调用.Wait()时,你基本上会要求你的代码运行一个常量循环”,这就是为什么我注意到“简化了,它不仅仅是这个”。这是一个实现细节,结果是一样的,只是性能更好,而且我所说的对一些人来说可能更容易理解,但感谢你的进一步解释:)老实说,我认为一个误导性的解释是不值得的,即使它更容易理解。任何人如果不知道等待是如何工作的,并把你的答案作为信息来源,就会学到一些以后不得不忘记的东西。我建议把这个有问题的部分从你的回答中去掉
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");