天天看點

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     }      

使用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     }      

TestAsync:

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

以上死鎖的原因:

  • 主執行線程調用子線程後挂起等待子線程結果
  • 子線程又需要切換到主線程或者等待主線程傳回
  • 進而導緻兩個線程均處在阻塞狀态(死鎖)

如何避免:

如果已經使用了Async/Await,那盡量不要再使用Task.Wait()/Task.Result,讓上下遊的方法全部改為Async/Await原則

參考資料:

  • Async/Await異步程式設計中的最佳做法