c# - Winforms调用async方法挂掉程序

标签 c# async-await deadlock

我已经解决这个问题一段时间了,但现在我真的很想知道哪里出了问题。我有一个相当简单的应用程序(它是一个用于 youtrack 的 turtoise SVN 插件,但我可以使用一个简单的 winforms 应用程序重现该问题)。

我有一个异步方法 ResolveIssue

public async Task<bool> ResolveIssue(Issue issue, int revision, string[] pathList)
{
    await Task.Delay(1000);

    return true;
}

要创建死锁,我要做的就是在 Button 事件处理程序中调用此异步方法,然后调用 Task.WaitTask.Result,像这样

private void buttonOk_Click(object sender, System.EventArgs e)
{
    var asyncResolvedIssue = api.ResolveIssue(issue, revision, pathList);
    if (asyncResolvedIssue.Result) {} // <== deadlock!
}

现在我明白拥有一个异步方法并主动等待它是相当奇怪的,但为什么它会产生死锁?!

最佳答案

您的问题是因为您在调用 .Result 时阻塞了 UI 线程,并且您告诉 Task.Delay 之后的延续在 UI 线程上运行。因此,您正在阻塞 UI 等待等待 UI 空闲时被阻塞的任务,这是一个典型的死锁。

两种解决方案。首先也让按钮点击异步。

private async void buttonOk_Click(object sender, System.EventArgs e)
{
    var asyncResolvedIssue = api.ResolveIssue(issue, revision, pathList);
    if (await asyncResolvedIssue) {} // <== no deadlock!
}

事件处理程序是唯一允许您执行 async void 的地方。

另一个选项是通过设置 ConfigureAwait(bool) 告诉 Task.Delay 它不需要在 UI 线程上运行其余功能。为假。

public async Task<bool> ResolveIssue(Issue issue, int revision, string[] pathList)
{
    await Task.Delay(1000).ConfigureAwait(false);

    return true;
}

现在 Task.Delay 之后的代码行将在线程池线程而不是 UI 线程上运行,并且不会因为 UI 线程当前被阻塞而被阻塞。

关于c# - Winforms调用async方法挂掉程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25456194/

相关文章:

c# - 从 LINQ 查询结果填充 Observable 集合

algorithm - 为什么 Ricart-Agrawala 算法没有死锁?

mysql - 为什么这是一个死锁(使用 InnoDB 的 MySQL)

reactjs - 将 history.block 与异步函数/回调/异步/等待一起使用

c# - 如何在 C# 中创建异步方法?

mysql - jpaRepository 出现死锁

C# Winforms 如何在函数中更新 toolStrip

c# - 折线图 - 更改边框宽度会删除空间

c# - 可以将 SQLCommand 作为参数传递吗?

ios - 为什么此任务等待离开 Xamarin iOS 中的 UI 上下文?