所以我试图让一个驱动程序在WinForms应用程序中工作(我希望我可以去WPF,但这不是一个选项)并且我遇到了一个有趣的问题。在驱动程序中调用await方法时,UI线程将永久阻塞。这是我的问题的一个非常简化的版本,这似乎只发生在Windows窗体应用程序上。
private void button_Click(object sender, EventArgs e)
{
MessageBox.Show(this.TestSynchronous().ToString());
}
// I'm trying to avoid having to change the code below
private int TestSynchronous()
{
return this.TestAsync().Result;
}
private async Task<int> TestAsync()
{
await Task.Delay(100);
var rand = new Random();
return rand.Next();
}
有没有办法可以将呼叫包裹到&#39; TestSynchronous&#39;防止它永久阻塞UI线程的方法?请记住,我试图避免不得不改变“测试”。任何方式的方法。
我看过像await works but calling task.Result hangs/deadlocks这样的重复类似帖子,这些帖子与我的问题类似,但我的问题无法以同样的方式解决。原因是他可以直接访问等待的异步方法,而我却没有。重申一下,我打电话给一个只向我提供“测试同步”的图书馆。方法,我想知道是否有任何方法可以包装方法,因此它不会阻塞某个地方进入库,我无法访问更改代码。
答案 0 :(得分:7)
在驱动程序中调用await方法时,UI线程会永远阻塞。
您正在我的博客上遇到我完整描述的common deadlock problem。简而言之,await
捕获&#34;背景&#34;并使用它来恢复其async
方法。 WinForms有一个SynchronizationContext
在UI线程上恢复。当您通过调用Result
阻止 UI线程时,async
方法无法恢复,因此存在死锁。
有没有办法可以将呼叫包裹到&#39; TestSynchronous&#39;防止它永久阻塞UI线程的方法?
无解决方案 适用于所有情况。
最佳方法是允许async
在代码库中自然增长:
private async Task<int> TestNoLongerSynchronousAsync()
{
return await this.TestAsync();
}
private async void button_Click(object sender, EventArgs e)
{
MessageBox.Show((await this.TestNoLongerSynchronousAsync()).ToString());
}
无论你认为这有多难,它几乎肯定比做同步异步黑客更容易。
如果您无法使用await
(对于非常强大的定义&#34;可以&#39;#&#34;) ,然后你可以使用我brownfield async article中描述的其中一个黑客:
Task.Run(() => this.TestAsync()).Result
)。这些都不适用于所有情况。在某些情况下,没有解决方案。祝你好运。
答案 1 :(得分:0)
所以我实际上能够解决这个问题,答案其实很简单。以下是该示例的修改版本。
private void button_Click(object sender, EventArgs e)
{
var task = Task.Run<int>(
() => this.TestSynchronous());
task.Wait();
MessageBox.Show(task.Result.ToString());
}
还有其他方法可以有效地做同样的事情,但这似乎适用于我的问题。有趣的是我之前(在发布我的问题之前)尝试使用类似的方法修复它并且它不起作用但它现在确实如此,所以我不知道我做错了什么。