天天看點

C# 死鎖 TaskCompletionSource

在異步轉同步時,使用不當容易造成死鎖(程式卡死)

看如下案例:

有一個異步方法

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

為何會死鎖?

猜測可能與Task.wait()類似的死鎖,詳細如下:

  1. UI線程調用子線程并等待子線程結果,
  2. 子線程執行過程中,切換到了UI線程(因為TestAsync是在UI線程運作的)
  3. 進而導緻兩個線程均處在阻塞狀态(死鎖)

關鍵字:死鎖、TaskCompletionSource