在異步轉同步時,使用不當容易造成死鎖(程式卡死)
看如下案例:
有一個異步方法
1 private static async Task TestAsync()
2 {
3 Debug.WriteLine("異步任務start……");
4 await Task.Delay(2000);
5 Debug.WriteLine("異步任務end……");
6 }
在執行如上異步方法時,嘗試将其轉換為同步方法
按照官方文檔《使用任務簡化異步程式設計》,TaskCompletionSource使用步驟:
- 擷取var sourceTask =TaskCompletionSource.Task,
- 等待此sourceTask結果-sourceTask.Result
- 設定設定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 }
但是,以上邏輯執行時,界面會卡死!卡死效果如下,卡死的時候點選界面其它按鈕無任何反應。

為何會死鎖?
猜測可能與Task.wait()類似的死鎖,詳細如下:
- UI線程調用子線程并等待子線程結果,
- 子線程執行過程中,切換到了UI線程(因為TestAsync是在UI線程運作的)
- 進而導緻兩個線程均處在阻塞狀态(死鎖)
關鍵字:死鎖、TaskCompletionSource