Semaphore類可以控制某個資源允許通路的線程數,Semaphore有命名式的,也有不命名的;如果不考慮跨程序工作,一般在代碼中使用不命名方式即可。
信号量有點類似于等待句柄,某個線程如果調用了WaitOne方法,這個線程就會暫停,并且等待有可用的信号量時才會繼續執行;某個線程調用Release方法,就會釋放一個信号計數值,每調用一次就釋放一個,如果想一次性釋放N個信号,可以調用Release(int)重載,把要釋放的數量傳遞給方法參數,但這個數值不能超過Semaphore執行個體化時所指定的最大值,否則會引發異常。
Semaphore構造函數可以指定允許的最大信号量,以及預設的信号量。聲明如下:
Semaphore(int initialCount, int maximumCount);
maximumCount參數指定該對象允許的最大信号量;initialCount參數指定預設值,這個預設值不能超過maximumCount指定的最大值。即該Semaphore執行個體預設允許多少個線程收到信号(通路資源)。
當某個占用資源的線程調用Release方法後,它會釋放出一個或多個信号,這時候,其他等待的線程就可以繼續執行。
隻要是涉及到線程問題都特别難說清楚,相當抽象,相當考驗人的了解能力。
比如,圖書館裡面有五本《X瓶梅》,但想借這本書的有20人。前面五個人自然很輕松就借到(進入通路圈,這五個線程以外的線程等待),其他人隻好等了。
過了幾天後,有個家夥通宵看書,終于看完了,是以他還了書,這時候,剩下的15個人看誰的動作快,可以借到剛還回去的這本書。
再過了幾天,又有兩個人看完了,還書。此時,剩下的14個人中,有兩個人可以借得此書。
大概的原理就是這樣,下面看看例子。
class Program
{
// 生成随機數,以延遲每個任務的執行時間
static Random rand = new Random();
// 聲明Semaphore變量,以控制線程信号量
static Semaphore sm = null;
static void Main(string[] args)
{
sm = new Semaphore(1, 4); //執行個體化
// 啟動10個任務
for (int i = 0; i < 10; i++)
{
Task t = new Task(DoWork, "任務" + (i + 1));
t.Start();
}
// 防止DOS視窗立即退出
Console.Read();
}
private static async void DoWork(object p)
{
sm.WaitOne(); //等待花開
string tn = p?.ToString();
Console.WriteLine($"{tn} 已獲得通路。");
await Task.Delay(rand.Next(1, 10) * 1000);
// 釋放
sm.Release(); //花謝了
Console.WriteLine($"{tn}已釋放。");
}
}
多線程開發我最喜歡用Task類,友善簡單強大好用高大上,而且它還能自行處理CPU多個核的問題。在上面例子中,有10個任務要執行,但我所執行個體化的Semaphore對象給的最大通路線程數為4,而預設狀态下隻允許1個線程同時通路。
是以,10個任務啟動後,其中一個會搶到通路權,其他任務就等吧。這時候Semaphore對象可通路數為0。因為預設隻允許1,現在有一個線程搶了,是以剩下就是0個通路權了。
當這個搶到通路權的任務調用Release方法後,通路權被釋放,這時候剩下的9個任務就開始搶,誰搶到誰就執行……依此類推。
看看運作結果。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL0YjN4MjM3ITM3EjMxUTMvwFOwUTMwIzLclDOzcjNz8CX1EDMyc2bsJ2Lc12bj5ycn9Gbi52YuAzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
任務1手快,它先搶到了通路權,于是它dododo,do完後,調用Release方法釋放,然後任務3人品好,就搶到了通路權,然後XXXXX,X完後調用Release釋放。其他線程繼續搶……
估計看完以上例子後,大家應該有點頭緒了。
現在,我們把上面的代碼改一下,在初始化Semaphore對象時的預設值從1改為3。
sm = new Semaphore(3, 4);
預設允許3個線程同時通路資源,最大數量為4。
然後再次運作,結果如下:
因為預設允許3個線程同時進入,是以在輸出結果中,前面三個任務都能擷取通路權,而其他的任務隻能等待機會。目前面已獲得資源的三個任務中有一個或者N個進行釋放後,剩下的任務又開始搶機會。
本文示例下載下傳位址:https://files.cnblogs.com/files/tcjiaan/DemoApp.zip