Winforms 调用异步方法挂断程序 [英] Winforms call to async method hangs up program

查看:11
本文介绍了Winforms 调用异步方法挂断程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have been working around this problem for a while, but now I would really like to understand what goes wrong. I have a rather simple application (it's a turtoise SVN plugin for youtrack, but I can reproduce the problem with a trivial winforms app).

我有一个异步方法 ResolveIssue

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

    return true;
}

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

All I have to do to create a deadlock is call this async method in a Button event handler, and call Task.Wait or Task.Result, like this

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

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

Now I understand it's rather weird to have an async method and actively wait for it, but why would it generate a deadlock?!

推荐答案

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

Your problem is because you are blocking the UI thread when you call .Result and you told the continuation after Task.Delay to run on the UI thread. So you are blocking the UI waiting for a task that is blocked on waiting for the UI to become free, a classic deadlock.

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

Two solutions. First make the button click async too.

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

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

Event handlers are the only place you are allowed to do async void.

另一个选项是通过设置 ConfigureAwait(bool) 为假.

The other option is tell Task.Delay it does not need to have the rest of its function run on the UI thread by setting ConfigureAwait(bool) to false.

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

    return true;
}

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

Now the line of code after the Task.Delay will run on a threadpool thread instead of the UI thread and will not be blocked by the fact that the UI thread is currently blocked.

这篇关于Winforms 调用异步方法挂断程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆