C#線程同步的三類情形剖析。本站提示廣大學習愛好者:(C#線程同步的三類情形剖析)文章只能為提供參考,不一定能成為您想要的結果。以下是C#線程同步的三類情形剖析正文
本文實例講述了C#線程同步的三類情形,分享給年夜家供年夜家參考。詳細剖析以下:
C# 曾經供給了我們幾種異常好用的類庫如 BackgroundWorker、Thread、Task等,借助它們,我們就可以夠分分鐘編寫出一個多線程的運用法式。
好比如許一個需求:有一個 Winform 窗體,點擊按鈕後,會將窗體中的數據導出到一個 output.pdf 文件中。本來的代碼沒有采取多線程技巧,所以當點擊按鈕後,全部窗體就釀成無呼應了。為懂得決這個成績,可使用 Task.Run(()=>{...導出文件的代碼});
下面的代碼看似簡略,卻隱蔽著各種危機。假如在導出的時代,窗體的數據被修正了,那會怎樣樣?假如多個窗體同時導出到統一個文件,又會怎樣樣?
在看完本系列後,你就會清晰了。
有點懂得的同伙都曉得線程同步有多種手腕,甚麼 mutex、moniter、seamphore、event 等等,我把它們歸為三類,對應三種須要線程同步的情形。
情形一:此茅坑有主了
當一個資本同時被多個線程拜訪時,有能夠會形成資本抵觸(特別是在存在多個寫線程的時刻)的情形。碰到這類情形,在 C# 中,我們可使用 Interlocked、lock、Moniter、SpinLock、ReadWriteLockSlim、Mutex 來處置成績。
甚麼情形下會被以為是情形一?
當你設計的類中湧現靜態變量、IO操作時,就會碰到情形一。由於這些資本是由多個對象同享的,分歧的線程很同時去拜訪這些資本時,便可能會湧現爭用。
當一個類被設計成單例,且包括實例變量時,也會碰到情形一。由於實例變量屬於這個單例,當多個線程把持此單例時,該變量能夠會被爭用。
當一個類中的辦法挪用線程操作某個實例變量時,也會碰到情形一。
情形二:數目無限,先到先得
情形一強調的是一對多的情況,而在情形二中,資本的數目其實不獨一。比擬於情形一,情形二著重的是數目上的限制。而用於完成這一需求的類有:Semaphore、SemaphoreSlim。
甚麼情形下會被以為是情形二?
當所操作的公共資本存在並發數限制的時刻(如數據庫銜接、IIS銜接數限制等),就被以為是情形二。
情形三:我讓你動,你能力動!
情形三存眷的是線程履行進程中的前後次序,而用於包管這類前後次序的方法就是經由過程線程通訊的方法:ManualResetEventSlim、ManualResetEvent、AutoResetEvent。
甚麼情形下會被以為是情形三?
當兩個線程所處置的工作有前後的依附時,好比線程二的履行進程依附線程一的履行成果,那就以為是情形三。
不限應用情形
下面的各類計劃其實不是相對只限於某一場景,好比 AutoResetEvent 便可以用於情形三,也能夠用於情形一。然則,殺雞焉用牛刀,固然應用 AutoResetEvent 可以或許完成情形一的需求,然則用不了 AutoResetEvent 的線程通訊才能,同時又會有一些額定的限制(每一個線程必需包管 wait 和 set 的成對應用,不然一個線程在鎖定資本後便可能被另外一個線程解鎖)。
lock (m)
{
//....
}
//等價於以下方法
autoResetEvent.WaitOne();
//....
autoResetEvent.Set();
也有同伙說,可以用情形一中的 lock 計劃來完成情形三的需求。
AutoResetEvent autoReset = new AutoResetEvent(false);
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
autoReset.WaitOne();
Console.WriteLine("步調二");
});
Thread.Sleep(1000);//有意延遲從而包管第二個線程是在第一個線程以後才履行
Task.Run(() =>
{
Console.WriteLine("步調一");
autoReset.Set();
});
}
下面這個例子終究輸入的成果可想而知。此實例解釋,不論線程現實的履行次序若何,AutoResetEvent 都能很輕易的包管兩個線程的履行次序。
假如用 lock 呢?
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
lock (s)
{
Console.WriteLine("步調一");
}
});
Thread.Sleep(1000);//必需工資確保步調二的線程要在步調一的線程以後履行
Task.Run(() =>
{
lock (s)
{
Console.WriteLine("步調二");
}
});
}
固然能完成,然則須要消費額定的代碼去工資包管兩個線程的履行次序。
若何在這麼多計劃中肯定終究所應用的,須要你能對項目標各類情形停止剖析,依據現實情形選擇對應的計劃,而不至於年夜材小用。
總 結
經由過程本系列文章的引見,信任能讓年夜家能對多線程中能夠碰著的情形有一個概念,不至於在面對多線程的時刻驚慌失措。
願望本文所述對年夜家的C#法式設計有所贊助。