前兩篇簡單介紹了執行緒同步lock,monitor,同步事件eventwaithandler,互斥體mutex的基本用法,在此基礎上,我們對 它們用法進行比較,並給出什麼時候需要鎖什麼時候不需要的幾點建議。最後,介紹幾個fcl中線程安全的類,集合類的鎖定方式等,做為對執行緒同步系列的完善 和補充。
lock和monitor是.net用乙個特殊結構實現的,monitor物件是完全託管的、完全可移植的,並且在作業系統資源要求方 面可能更為有效,同步速度較快,但不能跨程序同步。lock(monitor.enter和monitor.exit方法的封裝),主要作用是鎖定臨界區,使臨 界區**只能被獲得鎖的執行緒執行。monitor.wait和monitor.pulse用於執行緒同步,類似訊號操作,個人感覺使用比較複雜,容易造成死 鎖。
互斥體mutex和事件物件eventwaithandler屬於核心物件,利用核心物件進行執行緒同步,執行緒必須要在使用者模式和核心模 式間切換,所以一般效率很低,但利用互斥物件和事件物件這樣的核心物件,可以在多個程序中的各個執行緒間進行同步。
互斥體mutex類似於乙個接力棒,拿到接力棒的執行緒才可以開始跑,當然接力棒一次只屬於乙個執行緒(thread affinity),如果這個執行緒不釋放接力棒(mutex.releasemutex),那麼沒辦法,其他所有需要接力棒執行的執行緒都知道能等著看熱 鬧。
eventwaithandle 類允許執行緒通過發訊號互相通訊。 通常,乙個或多個執行緒在 eventwaithandle 上阻止,直到乙個未阻止的執行緒呼叫 set 方法,以釋放乙個或多個被阻止的執行緒。
首先要理解鎖定是解決競爭條件的,也就是多個執行緒同時訪問某個資源,造成意想不到的結果。比如,最簡單的情況是,乙個計數器,兩個執行緒 同時加一,後果就是損失了乙個計數,但相當頻繁的鎖定又可能帶來效能上的消耗,還有最可怕的情況死鎖。那麼什麼情況下我們需要使用鎖,什麼情況下不需要 呢?
1)只有共享資源才需要鎖定
只有可以被多執行緒訪問的共享資源才需要考慮鎖定,比如靜態變數,再比如某些快取中的值,而屬於執行緒內部的變數不需要鎖定。
2)多使用lock,少用mutex
如果你一定要使用鎖定,請盡量不要使用核心模組的鎖定機制,比如.net的mutex,semaphore,autoresetevent和 manuresetevent,使用這樣的機制涉及到了系統在使用者模式和核心模式間的切換,效能差很多,但是他們的優點是可以跨程序同步執行緒,所以應該清 楚的了解到他們的不同和適用範圍。
4)把鎖定交給資料庫
數 據庫除了儲存資料之外,還有乙個重要的用途就是同步,資料庫本身用了一套複雜的機制來保證資料的可靠和一致性,這就為我們節省了很多的精力。保證了資料來源 頭上的同步,我們多數的精力就可以集中在快取等其他一些資源的同步訪問上了。通常,只有涉及到多個執行緒修改資料庫中同一條記錄時,我們才考慮加鎖。
5)業務邏輯對事務和執行緒安全的要求
這 條是最根本的東西,開發完全執行緒安全的程式是件很費時費力的事情,在電子商務等涉及金融系統的案例中,許多邏輯都必須嚴格的執行緒安全,所以我們不得不犧牲 一些效能,和很多的開發時間來做這方面的工作。而一般的應用中,許多情況下雖然程式有競爭的危險,我們還是可以不使用鎖定,比如有的時候計數器少一多一, 對結果無傷大雅的情況下,我們就可以不用去管它。
interlocked 類提供了同步對多個執行緒共享的變數的訪問的方法。如果該變數位於共享記憶體中,則不同程序的執行緒就可以使用該機制。互鎖操作是原子的,即整個操作是不能由相 同變數上的另乙個互鎖操作所中斷的單元。這在搶先多執行緒作業系統中是很重要的,在這樣的作業系統中,執行緒可以在從某個記憶體位址載入值之後但是在有機會更改 和儲存該值之前被掛起。
我們來看乙個interlock.increment()的例子,該方法以原子的形式遞增指定變數並儲存結果,示例如下:
class
interlockedtest
}public
static
void
main(
string
args)}
輸出結果200000000,如果interlockedtest.add()方法中用注釋掉的語句代替interlocked.increment() 方法,結果將不可預知,每次執行結果不同。interlockedtest.add()方法保證了加1操作的原子性,功能上相當於自動給加操作使用了 lock鎖。同時我們也注意到interlockedtest.add()用時比直接用+號加1要耗時的多,所以說加鎖資源損耗還是很明顯的。
另外interlockedtest類還有幾個常用方法,具體用法可以參考msdn上的介紹。
.net在一些集合類,比如queue、arraylist、hashtable和stack,已經提供了乙個供lock使用的物件syncroot。用 reflector檢視了syncroot屬性(stack.synchroot略有不同)的原始碼如下:
public
virtual
object
syncroot
return
this
._syncroot;}}
這裡要特別注意的是msdn提到:從頭到尾對乙個集合進行列舉本質上並不是乙個執行緒安全的過程。即使乙個集合已進行同步,其他執行緒仍可以修改該集合,這將 導致列舉數引發異常。若要在列舉過程中保證執行緒安全,可以在整個列舉過程中鎖定集合,或者捕捉由於其他執行緒進行的更改而引發的異常。應該使用下面的**:
//在多執行緒環境中只要我們用下面的 方式例項化hashtable就可以了
hashtable ht
=hashtable.synchronized(
newhashtable());
//以下**是.net framework class library實現,增加對 synchronized的認識
[hostprotection(securityaction.linkdemand, synchronization
=true
)]public
static
hashtable synchronized(hashtable table)
return
newsynchashtable(table);}//
synchashtable的幾個常用方法,我們可以看到內部實現都加了lock關鍵字 保證執行緒安全
public
override
void
add(
object
key,
object
value)
}public
override
void
clear()
}public
override
void
remove(
object
key)}
C 執行緒鎖使用全功略
前兩篇簡單介紹了執行緒同步lock,monitor,同步事件eventwaithandler,互斥體mutex的基本用法,在此基礎上,我們對 它們用法進行比較,並給出什麼時候需要鎖什麼時候不需要的幾點建議。最後,介紹幾個fcl中線程安全的類,集合類的鎖定方式等,做為對執行緒同步系列的完善 和補充。l...
c 執行緒鎖,mutex lock使用
為什麼要用執行緒鎖呢.比如當乙個執行緒再修改乙個變數,另乙個執行緒在讀取那個變數,那麼讀到的值可能是乙個無法 的值,因為有可能他在讀的時候另乙個執行緒正寫到一半.由於執行緒導致的bug會比較難查詢,因此寫乙個靠譜的執行緒鎖非常重要.總結一下mutex lock相關函式 int pthread mut...
C 操作Word完全功略
前提 匯入com庫 microsoft word 11.0 object library.引用裡面就增加了 建立新word object newtrue odoc oword.documents.add refomissing,refomissing,refomissing,refomissing ...