.Net多線程編程中的誤用點分析

來源:互聯網
上載者:User
本文主要介紹了.Net多線程編程中的誤用點分析。具有一定的參考價值,下面跟著小編一起來看下吧

1 共用變數問題

錯誤寫法:

所有的任務可能會共用同一個變數,所以輸出結果可能會一樣。

public static void Error(){   for(int i=0;i<10;i++)   {    Task.Run(() => { Console.WriteLine("{0}", i); });   }}

正確寫法:

將變數i賦給局部變數temp,使得每一個任務使用不同的i值。

public static void Right(){   for (int i = 0; i < 10; i++)   {    int temp = i;    Task.Run(() => { Console.WriteLine("{0}", temp); });   }}

2 不要清理掛起任務所需資源

錯誤寫法:

非同步輸出常值內容,所以在未使用完StreamReader的時候,變數sr已經離開它的範圍,調用Dispose方法。

public static void Error(){   using (StreamReader sr = new StreamReader(@"D:\說明.txt", Encoding.Default))   {    Task.Run(() => { Console.WriteLine("輸出:{0}",sr.ReadLine()); });   }}

正確寫法:

public static void Right(){   using (StreamReader sr = new StreamReader(@"D:\說明.txt", Encoding.Default))   {    var task = Task.Run(() => { Console.WriteLine("輸出:{0}", sr.ReadLine()); });    task.Wait();   }}

3 避免鎖定this,typeof(type),string

正確的做法:定義一個object類型的私人唯讀欄位,鎖定之。

4 關於WaitHandle.WaitAll的waitHandles的數目必須小於等於64個

public static void Error(){   ManualResetEvent[] manualEvents = new ManualResetEvent[65];   try   {    for (int i = 0; i < 65; i++)    {     var temp = i;     Task.Run(() =>     {      manualEvents[temp] = new ManualResetEvent(false);      Console.WriteLine("{0}", temp);      manualEvents[temp].Set();     });    }    WaitHandle.WaitAll(manualEvents);   }   catch (Exception ae)   {    Console.WriteLine(ae.Message);   }}

5 無法捕獲異常的情形

try{    var task = Task.Run(() => { throw new Exception("拋異常"); });    //如果將下面這行代碼注掉,則無法拋出異常    task.Wait();}catch(Exception ex){    Console.WriteLine(ex.Message);}

6 是否該釋放Task資源

建議調用Dispose,但不調用也不是一個嚴重的錯誤。

注意在Task任務處於某些狀態時是不允許釋放資源的,否則會報錯。

public static void CatchException(){   try   {    Console.WriteLine("開始");    var task = Task.Run(() =>    {     //throw new Exception("拋異常");     });    //注掉下面這行代碼,觀察異常結果    //task.Wait();    task.Dispose();    Console.WriteLine("結束");   }   catch(Exception ex)   {    Console.WriteLine(ex.Message);   }}

7 死結示範

假設tsak1和task2都在獲得第二個鎖(對tsak1來說它請求的第二個鎖是LockedObj2 ,而對task2來說則是LockedObj1 )之前成功獲得了第一個鎖,就會發生死結。

private static readonly Object LockedObj1 = new object();private static readonly Object LockedObj2 = new object();public static void LockShow(){   var task1 = Task.Run(() =>    {    lock (LockedObj1)    {     Console.WriteLine("get LockedObj1");     lock (LockedObj2)     {      Console.WriteLine("get LockedObj2....");     }    }   });   var task2 = Task.Run(() =>   {    lock (LockedObj2)    {     Console.WriteLine("get LockedObj2");     lock (LockedObj1)     {      Console.WriteLine("get LockedObj1....");     }    }   });}

多次運行可得下面兩種結果:第一個圖是未發生死結的情形,第二個圖是發生死結的情形。

8 不要調用Thread.Abort方法。

Task沒有提供Abort方法,使用新的TPL(.NET 4.0以後),不會想到這個問題,一般使用CancellationToken來控製取消任務。

9 確保共用變數是安全的

反覆運行,可觀察到不一樣的結果,所示。

public static void Func(){   string s = "ASDFGH";   Parallel.Invoke(    () => { s = s.Replace("A", "1"); s = s.Replace("S", "1s"); },     () => { s = s.Replace("A", "2"); s = s.Replace("S", "2s"); },     () => { s = s.Replace("A", "3"); });   Console.WriteLine(s);}

10 處理器超額申請與申請不足

public static void Func(){   ParallelOptions po = new ParallelOptions();   //超額申請,處理器只有4個邏輯核心,結果設定並行度為10且是個邏輯核心均在工作,等待的任務數量大於0.   po.MaxDegreeOfParallelism = 10;   //申請不足,處理器有4個邏輯核心,卻指定並行度為3,還有一個閒置核心沒有被佔用(也有可能被其他線程佔用,這裡假設在指定並行度為3的情況下,另一個核心空閑)   po.MaxDegreeOfParallelism = 3;   List<int> list = new List<int>();   Parallel.ForEach(list, po, m =>   {    //業務   });}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.