.Net多線程編程(誤用點(diǎn)分析)
1 共享變量問題
錯(cuò)誤寫法:
所有的任務(wù)可能會(huì)共享同一個(gè)變量,所以輸出結(jié)果可能會(huì)一樣。
public static void Error()
{
for(int i=0;i<10;i++)
{
Task.Run(() => { Console.WriteLine("{0}", i); });
}
}
正確寫法:
將變量i賦給局部變量temp,使得每一個(gè)任務(wù)使用不同的i值。
public static void Right()
{
for (int i = 0; i < 10; i++)
{
int temp = i;
Task.Run(() => { Console.WriteLine("{0}", temp); });
}
}
2 不要清理掛起任務(wù)所需資源
錯(cuò)誤寫法:
異步輸出文本內(nèi)容,所以在未使用完StreamReader的時(shí)候,變量sr已經(jīng)離開它的作用域,調(diào)用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
正確的做法:定義一個(gè)object類型的私有只讀字段,鎖定之。
4 關(guān)于WaitHandle.WaitAll的waitHandles的數(shù)目必須小于等于64個(gè)
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資源
建議調(diào)用Dispose,但不調(diào)用也不是一個(gè)嚴(yán)重的錯(cuò)誤。
注意在Task任務(wù)處于某些狀態(tài)時(shí)是不允許釋放資源的,否則會(huì)報(bào)錯(cuò)。
public static void CatchException()
{
try
{
Console.WriteLine("開始");
var task = Task.Run(() =>
{
//throw new Exception("拋異常");
});
//注掉下面這行代碼,觀察異常結(jié)果
//task.Wait();
task.Dispose();
Console.WriteLine("結(jié)束");
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}

7 死鎖演示
假設(shè)tsak1和task2都在獲得第二個(gè)鎖(對(duì)tsak1來說它請(qǐng)求的第二個(gè)鎖是LockedObj2 ,而對(duì)task2來說則是LockedObj1 )之前成功獲得了第一個(gè)鎖,就會(huì)發(fā)生死鎖。
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....");
}
}
});
}
多次運(yùn)行可得下面兩種結(jié)果:第一個(gè)圖是未發(fā)生死鎖的情形,第二個(gè)圖是發(fā)生死鎖的情形。


8 不要調(diào)用Thread.Abort方法。
Task沒有提供Abort方法,使用新的TPL(.NET 4.0以后),不會(huì)想到這個(gè)問題,一般使用CancellationToken來控制取消任務(wù)。
9 確保共享變量是安全的
反復(fù)運(yùn)行,可觀察到不一樣的結(jié)果,下圖所示。
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 處理器超額申請(qǐng)與申請(qǐng)不足
public static void Func()
{
ParallelOptions po = new ParallelOptions();
//超額申請(qǐng),處理器只有4個(gè)邏輯內(nèi)核,結(jié)果設(shè)置并行度為10且是個(gè)邏輯內(nèi)核均在工作,等待的任務(wù)數(shù)量大于0.
po.MaxDegreeOfParallelism = 10;
//申請(qǐng)不足,處理器有4個(gè)邏輯內(nèi)核,卻指定并行度為3,還有一個(gè)空閑的內(nèi)核沒有被占用(也有可能被其他線程占用,這里假設(shè)在指定并行度為3的情況下,另一個(gè)內(nèi)核空閑)
po.MaxDegreeOfParallelism = 3;
List<int> list = new List<int>();
Parallel.ForEach(list, po, m =>
{
//業(yè)務(wù)
});
}
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!
- C#(asp.net)多線程用法示例(可用于同時(shí)處理多個(gè)任務(wù))
- .NET Framework中定時(shí)器timer的單線程與多線程使用講解
- .net面向?qū)ο笾嗑€程(Multithreading)及 多線程高級(jí)應(yīng)用
- 使用.Net實(shí)現(xiàn)多線程經(jīng)驗(yàn)總結(jié)
- .NET Windows 多線程thread編程
- 一些.NET對(duì)多線程異常處理技巧分享
- asp.net 計(jì)劃任務(wù)管理程序?qū)崿F(xiàn),多線程任務(wù)加載
- c#.net多線程編程教學(xué)——線程同步
- ASP.NET:一段比較經(jīng)典的多線程學(xué)習(xí)代碼
相關(guān)文章
Asp.net實(shí)現(xiàn)無刷新調(diào)用后臺(tái)實(shí)體類數(shù)據(jù)并以Json格式返回
本文主要分享了Asp.net實(shí)現(xiàn)無刷新調(diào)用后臺(tái)實(shí)體類數(shù)據(jù)并以Json格式返回的具體實(shí)例方法,具有一定的參考價(jià)值,有需要的朋友可以看下2016-12-12
在 .NET 項(xiàng)目中復(fù)制資源文件夾到生成目錄的方法
本文主要介紹在使用 Visual Studio 進(jìn)行調(diào)試和發(fā)布時(shí),如何在 .NET 項(xiàng)目中復(fù)制資源文件夾到生成目錄,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03
asp.net下linkbutton的前后臺(tái)使用方法
asp.net LinkButton傳遞參數(shù)2008-08-08
.Net Core+Angular Cli/Angular4開發(fā)環(huán)境搭建教程
這篇文章主要為大家詳細(xì)介紹了.Net Core+Angular Cli/Angular4開發(fā)環(huán)境搭建教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
iis的http 500內(nèi)部服務(wù)器錯(cuò)誤的解決
iis的http 500內(nèi)部服務(wù)器錯(cuò)誤是我們經(jīng)常碰到的錯(cuò)誤之一,它的主要錯(cuò)誤表現(xiàn)就是asp程序不能瀏覽但htm靜態(tài)網(wǎng)頁(yè)不受影響。另外當(dāng)錯(cuò)誤發(fā)生時(shí),系統(tǒng)事件日志和安全事件日志都會(huì)有相應(yīng)的記錄2007-04-04
ASP.NET中RadioButtonList綁定后臺(tái)數(shù)據(jù)后觸發(fā)點(diǎn)擊事件
這篇文章主要介紹了ASP.NET中RadioButtonList綁定后臺(tái)數(shù)據(jù)后觸發(fā)點(diǎn)擊事件的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-05-05

