侧边栏壁纸
博主头像
Tony's Blog博主等级

行动起来,coding

  • 累计撰写 83 篇文章
  • 累计创建 58 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录
c#

Winform_WPF async_await容易引起死锁的解决办法

Tony
2024-02-23 / 0 评论 / 0 点赞 / 62 阅读 / 3619 字

本文链接: https://blog.csdn.net/lishuangquan1987/article/details/125082082

在使用Winform或者WPF编程时,无论是使用.net framework 4.x还是使用.netcore 还是使用.net5,.net6,多多少少会使用到异步方法。如果是彻彻底底的使用异步,则不会发生死锁,但是有时候我们的系统框架都是用同步写的,突然第三方库只支持异步方法,这时候调用就要小心了,可能会引起界面卡死。

如下是模拟的情况:

新建一个winform项目。界面上有个按钮。点击这个按钮,调用异步方法。

代码如下:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var str = TestString().Result;
        MessageBox.Show(str);
    }
    public async Task<string> TestString()
    {
        await Task.Delay(2000);
        return "hello";
    }
}

你会发现,这个时候,界面卡主了,会永远一直卡下去。

具体的原因分析:https://wenku.baidu.com/view/4f6ab3d49d3143323968011ca300a6c30c22f16f.html

https://blog.csdn.net/WPwalter/article/details/78370706

假定 TestString 这个方法是别人第三方库提供的,那我们要如何调用

解决办法一(不推荐)

异步到底。全部使用异步。如果是小的项目,改一下无所谓。大的项目,不推荐:

public partial class Form1 : Form
{
	   public Form1()
	   {
	       InitializeComponent();
	   }

	   private async void button1_Click(object sender, EventArgs e)
	   {
	       var str =await TestString();
	       MessageBox.Show(str);
	   }
	   public async Task<string> TestString()
	   {
	       await Task.Delay(2000);
	       return "hello";
	   }
}

解决方案二(推荐)

使用 Task.Run 包一层

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private  void button1_Click(object sender, EventArgs e)
    {
        var (ok,str) =InvokeAsyncMethod(TestString,5000);
        if (ok)
        {
            MessageBox.Show(str);
        }
        else
        {
            MessageBox.Show("调用超时");
        }
    }
    public async Task<string> TestString()
    {
        await Task.Delay(2000);
        return "hello";
    }
    public (bool,T) InvokeAsyncMethod<T>(Func<Task<T>> func, int timeout)
    {
        var result = Task.Run(async () => await func());
        if (result.Wait(timeout))
        {
            return (true, result.Result);
        }
        else
        {
            return (false, default(T));
        }
    }
}

0

评论区