C# 死锁 Task/AutoResetEvent
与之前《C# 死锁 TaskCompletionSource》类似,还有很多死锁的案例
使用Task异步转同步时,使用不当造成的死锁
1 private void Task_OnClick(object sender, RoutedEventArgs e) 2 { 3 AwaitUsingTask(TestAsync()); 4 Debug.WriteLine("Task_OnClick end"); 5 } 6 private void AwaitUsingTask(Task task) 7 { 8 task.Wait(); 9 //task.Result; 10 }
TestAsync:
1 private static async Task TestAsync()
2 {
3 Debug.WriteLine("异步任务start……");
4 await Task.Delay(2000);
5 Debug.WriteLine("异步任务end……");
6 }
使用AutoResetEvent不当,造成的死锁
1 private void AwaitAutoResetEvent_OnClick(object sender, RoutedEventArgs e) 2 { 3 AwaitUsingAutoResetEvent(TestAsync()); 4 Debug.WriteLine("AwaitAutoResetEvent_OnClick end"); 5 } 6 7 public void AwaitUsingAutoResetEvent(Task task) 8 { 9 AutoResetEvent autoResetEvent = new AutoResetEvent(false); 10 11 task.ContinueWith(t => 12 { 13 autoResetEvent.Set(); 14 }); 15 autoResetEvent.WaitOne(); 16 }
以上死锁,是因为autoResetEvent.WaitOne(),锁住当前UI线程直到收到信号,但task是什么线程运行的?UI线程啊,所以task也被锁住了,所以就无法执行后面的逻辑autoResetEvent.Set()了。那会一直保持阻塞在那。
或者以终止状态=true为参数的AutoResetEvent,也是会死锁的,如下:
1 private int index = 0; 2 private async void AwaitAutoResetEvent_OnClick(object sender, RoutedEventArgs e) 3 { 4 await AwaitUsingAutoResetEvent(index++); 5 } 6 AutoResetEvent autoResetEvent = new AutoResetEvent(true); 7 public async Task AwaitUsingAutoResetEvent(int ind) 8 { 9 autoResetEvent.WaitOne(); 10 Debug.WriteLine($"Task.Delay(3000) start{ind}"); 11 await Task.Delay(3000); 12 Debug.WriteLine($"Task.Delay(3000) end{ind}"); 13 autoResetEvent.Set(); 14 }
上面的案例,2次重入,就会暴露死锁的问题了(因为首次是终止的,第二次才会wait)。
那么如何解决?autoResetEvent.WaitOne();放在异步任务中等待即可
当然此方案会多产生一个task(有性能问题),详见AutoResetEvent的正确用法:C# 同步转异步 AutoResetEvent
以上死锁的原因:
- 主执行线程调用子线程后挂起等待子线程结果
- 子线程又需要切换到主线程或者等待主线程返回
- 从而导致两个线程均处在阻塞状态(死锁)
如何避免:
如果已经使用了Async/Await,那尽量不要再使用Task.Wait()/Task.Result,让上下游的方法全部改为Async/Await原则
参考资料:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)