動機
從開始接觸多線(進)程編程模型開始學習的就是和信號量(Semaphore)相關的同步原語不知道為什麼 Net Framework 裡卻沒有相應的東東要命的是 我以前有很多久經考驗的C++代碼都是用她來實現的 為了不使革命先烈的藥白吃 血白流 只好自己生一個了
什麼是信號量(Semaphore)
如果你已經了解信號量(Semaphore)的概念了請跳過這一段
信號量(Semaphore)是在多線程環境下使用的一種設施 它負責協調各個線程 以保證它們能夠正確合理的使用公共資源
我們來看看一個停車場是怎樣運作的為了簡單起見假設停車場只有三個車位一開始三個車位都是空的這是如果同時來了五輛車看門人允許其中三輛不受阻礙的進入然後放下車攔剩下的車則必須在入口等待此後來的車也都不得不在入口處等待這時有一輛車離開停車場看門人得知後打開車攔放入一輛如果又離開兩輛則又可以放入兩輛如此往復
在這個停車場系統中車位是公共資源每輛車好比一個線程看門人起的就是信號量的作用
更進一步信號量的特性如下信號量是一個非負整數(車位數)所有通過它的線程(車輛)都會將該整數減一(通過它當然是為了使用資源)當該整數值為零時所有試圖通過它的線程都將處於等待狀態在信號量上我們定義兩種操作 Wait(等待) 和 Release(釋放) 當一個線程調用Wait等待)操作時它要麼通過然後將信號量減一要麼一自等下去直到信號量大於一或超時Release(釋放)實際上是在信號量上執行加操作對應於車輛離開停車場該操作之所以叫做釋放是應為加操作實際上是釋放了由信號量守護的資源
實現
大家都知道Net Framework類庫中提供的線程同步設施包括
Monitor AutoResetEvent ManualResetEventMutexReadWriteLock和 InterLock 其中 AutoResetEvent ManualResetEventMutex派生自WaitHandler它們實際上是封裝了操作系統提供的內核對象而其它的應當是在Net虛擬機中土生土長的顯然來自操作系統內核對象的設施使用起來效率要差一些不過效率並不是我們這裡要考慮的問題我們將使用兩個 Monitor 和 一個ManualResetEvent 對象來模擬一個信號量
代碼如下
public class Semaphore { private ManualResetEvent waitEvent = new ManualResetEvent(false)private object syncObjWait = new object()private int maxCount = //最大資源數private int currentCount = //當前資源數
public Semaphore()
{
}
public Semaphore( int maxCount )
{ thismaxCount = maxCount}
public bool Wait()
{ lock( syncObjWait ) //只能一個線程進入下面代碼{ bool waitResult = thiswaitEventWaitOne() //在此等待資源數大於零if( waitResult )
{ lock( this )
{ if( currentCount > )
{ currentCount——if( currentCount == )
{ thiswaitEventReset()}
} else { SystemDiagnosticsDebugAssert( false Semaphore is not allow current count < )} return waitResult}
/**//// <summary> /// 允許超時返回的 Wait 操作/// </summary> /// <param name=millisecondsTimeout></param> /// <returns></returns> public bool Wait( int millisecondsTimeout )
{ lock( syncObjWait ) // Monitor 確保該范圍類代碼在臨界區內{ bool waitResult = thiswaitEventWaitOne(millisecondsTimeoutfalse)if( waitResult )
{ lock( this )
{ if( currentCount > )
{ currentCount——if( currentCount == )
{ thiswaitEventReset()}
} else { SystemDiagnosticsDebugAssert( false Semaphore is not allow current count < )} return waitResult}
public bool Release()
{ lock( this ) // Monitor 確保該范圍類代碼在臨界區內{ currentCount++if( currentCount > thismaxCount )
{ currentCount = thismaxCountreturn false} thiswaitEventSet() //允許調用Wait的線程進入} return true}
}
From:http://tw.wingwit.com/Article/program/net/201311/13256.html