在异步转同步时,使用不当容易造成死锁(程序卡死)

看如下案例:

有一个异步方法

1     private static async Task TestAsync()
2 {
3 Debug.WriteLine("异步任务start……");
4 await Task.Delay(2000);
5 Debug.WriteLine("异步任务end……");
6

在执行如上异步方法时,尝试将其转换为同步方法

按照官方文档《​​使用任务简化异步编程​​》,TaskCompletionSource使用步骤:

  1. 获取var sourceTask =TaskCompletionSource.Task,
  2. 等待此sourceTask结果-sourceTask.Result
  3. 设置设置sourceTask.Result的结果值
1     private void TaskCompleteSourceDead_OnClick(object sender, RoutedEventArgs e)
2 {
3 AwaitByTaskCompleteSource(TestAsync());
4 Debug.WriteLine($"4. TaskCompleteSource_OnClick end");
5 }
6 private void AwaitByTaskCompleteSource(Task task)
7 {
8 var taskCompletionSource = new TaskCompletionSource<object>();
9 var taskFromSource = taskCompletionSource.Task;
10 task.ContinueWith(action =>
11 {
12 taskCompletionSource.SetResult(true);
13 });
14 var task1Result = taskFromSource.Result;
15 Debug.WriteLine($"3. AwaitByTaskCompleteSource end:{task1Result}");
16

但是,以上逻辑执行时,界面会卡死!卡死效果如下,卡死的时候点击界面其它按钮无任何反应。

C# 死锁 TaskCompletionSource_c#

为何会死锁?

猜测可能与Task.wait()类似的死锁,详细如下:

  1. UI线程调用子线程并等待子线程结果,
  2. 子线程执行过程中,切换到了UI线程(因为TestAsync是在UI线程运行的)
  3. 从而导致两个线程均处在阻塞状态(死锁)

 

关键字:死锁、TaskCompletionSource

 

参考资料:

同步转异步

异步转同步

死锁

作者:​​唐宋元明清2188​