C# 訊號量 學習
訊號量 (Semaphore),是負責協調各個執行緒, 以保證它們能夠正確、合理的使用公共資源。也是作業系統中用於控制程序同步互斥的量。
Semaphore常用的方法有兩個WaitOne()和Release(),Release()的作用是退出訊號量並返回前一個計數,而WaitOne()則是阻止當前執行緒,直到當前執行緒的WaitHandle 收到訊號。這裡我舉一個例子讓大家更容易理解:當我們這樣例項化Semaphore時候。
Semaphore sema = new Semaphore(x,y)
有一隊人排隊上洗手間,人就相當於執行緒,x為還剩餘的位置數量,y為總的位置數量。
WaitOne()方法就相當於人在等待洗手間位置的行為,而Release()方法就相當於一個人從洗手間出來的行為,這裡再假設x和y都為5,說明開始的時候洗手間有5個空位置,且總共只有5個位置,當一隊超過5個人的隊伍要上洗手間的就排隊,首先WaitOne()方法
public class Program
{
static Semaphore sema = new Semaphore(5, 5);
const int cycleNum = 9;
static void Main(string[] args)
{
for(int i = 0; i < cycleNum; i++)
Thread td = new Thread(new ParameterizedThreadStart(testFun));
td.Name = string.Format("編號{0}",i.ToString());
td.Start(td.Name);
}
Console.ReadKey();
}
public static void testFun(object obj)
{
sema.WaitOne();
Thread.Sleep(2000);
Console.WriteLine(obj.ToString() + "出洗手間:" + DateTime.Now.ToString());
sema.Release();
}
}
這裡我要說明一點,訊號量控制的只是執行緒同步的量,而不管順序,這個例子來說執行緒控制的就是執行緒同步量為5,也就是同時併發的執行緒數量為5個,至於是哪個先哪個後不是由這裡的訊號量決定的。
當然這個例子中因沒有做什麼複雜的操作,一般情況進入執行緒的時間和每個執行緒要的時間不會有太大差別,所以執行的順序還是很規律的(為了說明這個問題我也是運行了多次才讓結果稍有不同,這裡編號2搶在了編號1前面就是這個道理),如果執行緒中有很複雜的操作每個執行緒在執行中所用的時間有比較大的差別,或者迴圈開始有複雜操作那麼很可能就不是編號0先進入洗手間了,且不一定是先進入的就會先出來。
接下來再簡單介紹一下Semaphore的WaitOne()和Release()的過載方法
public int Release(int releaseCount);
releaseCount指的是釋放的訊號量數量,如果沒有引數預設為1,Release()就相當於Release(1)
這裡要說明一點,當Release()或者Release(int releaseCount)執行時導致訊號量計數大於最大數量時會丟擲SemaphoreFullException異常。下面這種情況就會異常:
Semaphore sem = new Semaphore(4,5); sem.Release(2);//這裡是釋放2個訊號量加上之前的4個,超出5個了
public virtual bool WaitOne(TimeSpan timeout); public virtual bool WaitOne(int millisecondsTimeout);
第一個過載引數timeout:指定時間間隔,若在這段時間內沒有接收到訊號則跳過等待繼續執行
第二個過載引數millisecondsTimeout:指定時間間隔整數毫秒,若在這段時間內沒有接收到訊號則跳過等待繼續執行
WaitOne()還有兩個過載方法不是很常用這裡就不介紹了。上面的過載方法這裡也不再進了案例說明了,有興趣的朋友可以自己嘗試一下。