【问题标题】:Winforms call to async method hangs up programWinforms调用异步方法挂起程序
【发布时间】:2014-08-22 22:05:12
【问题描述】:

我已经解决这个问题一段时间了,但现在我真的很想了解哪里出了问题。我有一个相当简单的应用程序(它是一个用于 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!
}

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

【问题讨论】:

  • 为什么投了 2 票?至少发表评论。

标签: c# async-await deadlock


【解决方案1】:

您的问题是因为您在调用 .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

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

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

    return true;
}

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

【讨论】:

  • 为我无法使我的点击事件处理程序异步而感到羞耻。
猜你喜欢
  • 1970-01-01
  • 2018-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-04
  • 1970-01-01
  • 2011-10-07
相关资源
最近更新 更多