本文主要是介绍winfrom 多线程卡死问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 原因分析
- 解决方式
- 一 添加 async await
- 二 添加同步方法去调用异步方法
原因分析
我们在执行一下代码的时候会发现程序卡死了,首先winform项目中能够修改控件的必须是UI线程,主线程遇到await返回后会将下面未执行的代码打包交给线程池,由线程池分配线程再处理,而因为winformUI线程的特殊性,丢给线程池后会有上下文环境的问题,而这个上下文环境的问题只有主线程会涉及到,所以打包后的内容优先由主线程来执行。而这个特殊性导致winform在await之后运行的线程一定是UI线程。
private void btnSync_Click(object sender, EventArgs e)
{Console.WriteLine($"This is btnSync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");var task = this.CalculationAsync(1_000_000);task.Wait();long lResult = task.Result;//同步阻塞,主线程在等结果//long lResult = this.GetCalculationAsync(1_000_000);//换个线程去调用async方法,有点恶心Console.WriteLine($"This is btnSync_Click End,ThreadId={Thread.CurrentThread.ManagedThreadId}");this.lblSync.Text = lResult.ToString();
}private async Task<long> CalculationAsync(long total)
{var result = await Task.Run(() =>{Console.WriteLine($"This is CalculationAsync Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");long lResult = 0;for (int i = 0; i < total; i++){lResult += i;}Console.WriteLine($"This is CalculationAsync End,ThreadId={Thread.CurrentThread.ManagedThreadId}");return lResult;});return result;//await后面的代码,会要求主线程来执行
}
解决方式
一 添加 async await
private async void btnAsync_Click(object sender, EventArgs e){Console.WriteLine($"This is btnAsync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");long lResult = await this.CalculationAsync(1_000_000);Console.WriteLine($"This is btnAsync_Click End,ThreadId={Thread.CurrentThread.ManagedThreadId}");this.lblAsyncResult.Text = lResult.ToString();//必须是UI线程,更新能成功是因为winform的UI线程特殊性,await之后的线程一定是UI线程
}
二 添加同步方法去调用异步方法
private long GetCalculationAsync(long total)
{var taskLong = Task.Run(() =>{var task = this.CalculationAsync(total);long lResult = task.Result;//子线程return lResult;});return taskLong.Result;//主线程在等Result
}
这篇关于winfrom 多线程卡死问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!