本系列意在記錄Windwos線程的相關知識點,包括線程基礎、線程調度、線程同步、TLS、線程池等
本篇介紹與核心對象同步相關的Event對象和Mutex對象
AutoResetEvent和ManualResetEvent
同步事件有兩種:AutoResetEvent和 ManualResetEvent。主要使用者線程之間的通知,實現同步。無論是哪種,實際上是每個Event對象關聯了一個事件核心對象。在【Windows】線程漫談——線程同步之等待函數和事件核心對象中,詳細介紹了事件核心對象和等待函數。.NET這裡的兩個版本是對它們的封裝。下面簡單回顧一下事件核心對象:
事件核心對象有兩種狀態:觸發狀態、非觸發狀態。等待函數用來檢測某種核心對象的狀態,當鎖檢測的核心對象是觸發狀態的時候等待函數將直接返回,否則將阻塞。(這樣的表述其實是不完整的,這裡只是簡單描述了一般的情境)。線程可以通過Set方法使事件對象變為觸發狀態,這樣如果有一個線程正在等待這個對象觸發,那麼相當於它將收到“事件通知”而返回。AutoReset的事件核心對象在被設定為觸發態後將自動回到非觸發態,ManualReset的事件對象不會自動重設為未觸發狀態。
.NET的封裝相應的有兩個版本,自動重設和手動重設,他們實際上是一樣的對象,只是行為稍有不同而已。在初始化事件對象的時候可以指定事件對象的初始化狀態:
static AutoResetEvent myResetEvent = new AutoResetEvent(false);//初始化為非觸發狀態
調用Set方法將事件對象置為觸發狀態:
event_1.Set();
調用Reset方法將事件對象置為非觸發狀態:
event_1.Reset();
調用WaitOne、WaitAny或WaitAll來使線程等待事件對象,它們的用法可以顧名思義。
下面對比一下.NET封裝的事件對象和windows原生的事件對象,關於windows原生的事件核心對象參見【Windows】線程漫談——線程同步之等待函數和事件核心對象
.NET |
Windows API |
說明 |
AutoResetEvent |
CreateEvent(bManualReset=false) |
|
ManualResetEvent |
CreateEvent(bManualReset=true) |
|
.Set |
SetEvent |
|
.Reset |
ResetEvent |
|
AutoResetEvent |
PulseEvent |
.NET沒提供PulseEvent,對於事件對象而言,用AutoResetEvent代替 |
-- |
Named |
.NET下事件對象似乎無法命名,也就是說事件對象不能跨進程。但是Windows原生的事件對象是跟其他核心對象一樣是可以命名的,因此可以跨進程共用 |
EventWaitHandle.WaitOne |
WaitForSingleObject |
.NET通過在基類EventWaitHandle中定義Wait系列函數,封裝了等待函數 |
EventWaitHandle.WaitAll |
WaitForMultipleObjects (bWaitAll=true) |
|
EventWaitHandle.WaitAny |
WaitForMultipleObjects (bWaitAll=false) |
|
Mutex
.NET下單Mutex和Win32下單Mutex就是同一個東西,所以,完全可以從Win32的互斥量核心對象來理解。跟通常的核心對象一樣,互斥量具有觸發和未觸發兩種。當對象為觸發狀態的時候,等待他的線程將獲得其訪問權,共置為未觸發狀態;反之,對象為未觸發狀態時,等待他的線程將掛起。與Monitor和lock相同,Mutex也有記錄所屬線程ID,使用計數和遞迴計數,因此,同一個線程可以多次獲得同一個Mutex的存取權限,但是要保證能夠有相同次數的釋放。
通過建構函式建立Mutex對象
private static Mutex mut = new Mutex();
除了不帶參數的建構函式,還有一些可選的參數用於建立Mutex對象:可以初始化建立的線程是否立刻擁有Mutex的存取權限、可以為Mutex命名,命名的Mutex可以對其他進程可見,而不僅僅是本進程的線程。關於命名MSDN還有如下的說明:
在運行終端服務的伺服器上,已命名的系統 mutex 可以具有兩級可見度。 如果名稱以首碼“Global\”開頭,則 mutex 在所有終端伺服器會話中均為可見。 如果名稱以首碼“Local\”開頭,則 mutex 僅在建立它的終端伺服器會話中可見。 在這種情況下,伺服器上各個其他終端伺服器會話中都可以擁有一個名稱相同的獨立 mutex。 如果建立已命名 mutex 時不指定首碼,則它將採用首碼“Local\”。 在終端伺服器會話中,只是名稱首碼不同的兩個 mutex 是獨立的 mutex,這兩個 mutex 對於終端伺服器會話中的所有進程均為可見。 即:首碼名稱“Global\”和“Local\”說明 mutex 名稱相對於終端伺服器會話(而並非相對於進程)的範圍。
通過Mutex.Wait系列函數嘗試獲得對Mutex的存取權限
mut.WaitOne();
通過Mutex.ReleaseMutex釋放Mutex
mut.ReleaseMutex();
在我之前的文章【Windows】線程漫談——線程同步之訊號量和互斥量中詳細闡述了Win32下互斥量對象,下面對兩種API作一個比較
.NET |
Windows API |
說明 |
Mutex |
CreateMutex |
|
Mutex |
OpenMutex |
|
.ReleaseMutex |
ReleaseMutex |
|
Mutex(bool,string) |
Named |
.NET下可以對Mutex對象命名 |
EventWaitHandle.WaitOne |
WaitForSingleObject |
.NET通過在基類EventWaitHandle中定義Wait系列函數,封裝了等待函數 |
EventWaitHandle.WaitAll |
WaitForMultipleObjects (bWaitAll=true) |
|
EventWaitHandle.WaitAny |
WaitForMultipleObjects (bWaitAll=false) |
|
勞動果實,轉載請註明出處:http://www.cnblogs.com/P_Chou/archive/2012/08/19/event-and-mutex-in-net-thread-sync.html