winfrom 多线程卡死问题

迷南。 2022-10-05 11:44 300阅读 0赞

目录

    • 原因分析
    • 解决方式
      • 一 添加 async await
      • 二 添加同步方法去调用异步方法

原因分析

  1. 我们在执行一下代码的时候会发现程序卡死了,首先winform项目中能够修改控件的必须是UI线程,主线程遇到await返回后会将下面未执行的代码打包交给线程池,由线程池分配线程再处理,而因为winformUI线程的特殊性,丢给线程池后会有上下文环境的问题,而这个上下文环境的问题只有主线程会涉及到,所以打包后的内容优先由主线程来执行。而这个特殊性导致winformawait之后运行的线程一定是UI线程。
  2. private void btnSync_Click(object sender, EventArgs e)
  3. {
  4. Console.WriteLine($"This is btnSync_Click Start,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
  5. var task = this.CalculationAsync(1_000_000);
  6. task.Wait();
  7. long lResult = task.Result;//同步阻塞,主线程在等结果
  8. //long lResult = this.GetCalculationAsync(1_000_000);//换个线程去调用async方法,有点恶心
  9. Console.WriteLine($"This is btnSync_Click End,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
  10. this.lblSync.Text = lResult.ToString();
  11. }
  12. private async Task<long> CalculationAsync(long total)
  13. {
  14. var result = await Task.Run(() =>
  15. {
  16. Console.WriteLine($"This is CalculationAsync Start,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
  17. long lResult = 0;
  18. for (int i = 0; i < total; i++)
  19. {
  20. lResult += i;
  21. }
  22. Console.WriteLine($"This is CalculationAsync End,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
  23. return lResult;
  24. });
  25. return result;//await后面的代码,会要求主线程来执行
  26. }

解决方式

一 添加 async await

  1. private async void btnAsync_Click(object sender, EventArgs e)
  2. {
  3. Console.WriteLine($"This is btnAsync_Click Start,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
  4. long lResult = await this.CalculationAsync(1_000_000);
  5. Console.WriteLine($"This is btnAsync_Click End,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
  6. this.lblAsyncResult.Text = lResult.ToString();//必须是UI线程,更新能成功是因为winform的UI线程特殊性,await之后的线程一定是UI线程
  7. }

二 添加同步方法去调用异步方法

  1. private long GetCalculationAsync(long total)
  2. {
  3. var taskLong = Task.Run(() =>
  4. {
  5. var task = this.CalculationAsync(total);
  6. long lResult = task.Result;//子线程
  7. return lResult;
  8. });
  9. return taskLong.Result;//主线程在等Result
  10. }

发表评论

表情:
评论列表 (有 0 条评论,300人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线09/线问题

    线程死锁问题 > 死锁 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁 出现死锁后,不会出现异常,不会出现提示,只