.NET 同步與異步 之 Mutex (十二)

本隨筆續接:.NET 同步與異步 之 線程安全的集合 (十一)html

本隨筆 及 接下來的兩篇隨筆,將介紹 .NET 同步與異步系列 的最後一個大塊知識點:WaitHandle家族。編程

抽象基類:WaitHandle, 三個子類: EventWaitHandle(Event通知) 、Mutex(進程同步鎖)、Semaphone (信號量),還有兩個孫子輩:System.Threading.AutoResetEventSystem.Threading.ManualResetEvent,都是 EventWaitHandle 的子類。安全

 

1、抽象基類 WaitHandle

[ComVisibleAttribute(true)]
public abstract class WaitHandle : MarshalByRefObject, IDisposable

經過上面的信息,咱們能夠知道 WaitHandle  繼承自 MarshalByRefObject, 並實現了 IDisposable 接口。app

對於 MarshalByRefObject ,你也許不是很熟悉,但它的不少子類你必定會用過的,讓咱們來揭開它的廬山真面目。異步

在MSND中是這樣描述 MarshalByRefObject 的:ide

應用程序域是一個操做系統進程中一個或多個應用程序所駐留的分區。同一應用程序域中的對象直接通訊。不一樣應用程序域中的對象的通訊方式有兩種:一種是跨應用程序域邊界傳輸對象副本,一種是使用代理交換消息。MarshalByRefObject 是經過使用代理交換消息來跨應用程序域邊界進行通訊的對象的基類。函數

看到這裏你也許更迷惑了,我用過它? 用過它的子類? 沒錯,就是用過它的子類,而且還不少。post

例如 System.Drawing命名空間的 Brush、Image、Pen、Font 等等,還有個你們更熟悉的 System.IO命名空間下的Stream.ui

延展閱讀:利用 MarshalByRefObject 實現 AOP this

看到這裏咱們只須要知道 WaitHandle 具備跨應用程序域進行通信的能力就能夠了。

 

2、Mutex(進程同步鎖)

一、MSDN對Mutex的定義爲進程間的同步基元, 即鎖的概念。

  反觀Monitor、平時只用來在應用程序域內的線程之間通訊。其實,若是用於鎖的對象派生自MarshalByRefObject,Monitor 也可在多個應用程序域中提供鎖定。

  Mutex因爲須要調用操做系統資源,所以執行的開銷比Monitor大得多,因此若是僅僅須要在應用程序內部的線程間同步操做,Monitor/lock應當是首選

 

二、Mutex 的用法

  • WaitOne() /WaitOne(TimeSpan, Boolean)及若干個重載:請求全部權,該調用會一直阻塞到當前 mutex 收到信號,或直至達到可選的超時間隔,這幾個方法都不須要提供鎖定對象做爲額外參數。
    • 您可使用 WaitHandle.WaitOne 請求全部權的互斥體的方法。 調用線程受到阻止,直到發生下列狀況之一︰
    • 互斥體發出信號以指示不擁有。 在此狀況下, WaitOne 方法將返回 true, ,調用線程的互斥體全部權,並訪問由 mutex 保護的資源。 線程完成後訪問資源,必須調用 ReleaseMutex 方法來釋放 mutex 的全部權。 

    • 對調用中指定的超時間隔 WaitOne 具備方法 millisecondsTimeout 或 timeout 參數已過。 在此狀況下, WaitOne 方法將返回 false, 此時該線程不會獲取互斥體的全部權。

  • ReleaseMutex():釋放當前 Mutex 一次。注意,這裏強調了一次,由於擁有互斥體的線程能夠在重複的調用WaitOne系列函數而不會阻止其執行;這個跟Monitor的Enter()/Exit()能夠在獲取對象鎖後能夠被重複調用同樣。Mutex被調用的次數由公共語言運行庫(CLR)保存,每WaitOne()一次計數+1,每ReleaseMutex()一次計數-1,只要這個計數不爲0,其它Mutex的等待者就會認爲這個Mutex沒有被釋放,也就沒有辦法得到該Mutex。 另外,跟Monitor.Exit()同樣,只有Mutex的擁有者才能RleaseMutex(),不然會引起異常。
  • 若是線程在擁有互斥體時終止,咱們稱此互斥體被遺棄(Abandoned)。在MSDN裏,微軟以警告的方式指出這屬於「嚴重的」編程錯誤。這是說擁有mutex的擁有者在得到全部權後,WaitOne()和RelaseMutex()的次數不對等,調用者自身又不負責任地停止,形成mutex 正在保護的資源可能會處於不一致的狀態。其實,這無非就是提醒你記得在try/finally結構中使用Mutex

 

三、全局和局部的Mutex

若是在一個應用程序域內使用Mutex,固然不如直接使用Monitor/lock更爲合適,由於前面已經提到Mutex須要更大的開銷而執行較慢。不過Mutex畢竟不是Monitor/lock,它生來應用的場景就應該是用於進程間同步的。用於在進程間通信的Mutex咱們稱爲全局Mutex,而只用於在應用程序域內部通信的Mutex、咱們稱爲局部Mutex.

全局Mutex和局部Mutex是經過構造函數來構造不一樣的實例的,讓咱們來看一下Mutex的構造函數,一共有5個,挑兩個具備表明性的看一下吧:

  • Mutex():用無參數的構造函數獲得的Mutex沒有任何名稱,而進程間沒法經過變量的形式共享數據,因此沒有名稱的Mutex也叫作局部(Local)Mutex。另外,這樣建立出的Mutex,建立者對這個實例並無擁有權,仍然須要調用WaitOne()去請求全部權。
  • Mutex(Boolean initiallyOwned, String name, out Booldan createdNew, MutexSecurity):第一個bool參數:指示初始化的實例是否擁有互斥體全部權。第二個string類型、爲互斥體指定一個名稱,若是string爲null或者空字符串 則至關於建立一個沒有名字的Mutex,當屬於局部Mutex. 而有名字的Mutex當屬於全局Mutex.第三個bool參數、若是已經初始化了互斥體 返回True, 若是互斥體已經存在則返回False. 最後一個參數用於Mutex訪問的安全性控制。

 

四、用途 

Mutex天生爲進程間的同步基元,所以它能夠用來控制應用程序的單實例

/// <summary>
/// 單實例運行
/// </summary>
/// <returns> true 應用程序已啓動,false 則沒有 </returns>
public bool SingleRun(ref System.Threading.Mutex mutex )
{
    mutex = new System.Threading.Mutex(false, "WINDOWS");
    if (!mutex.WaitOne(0, false))
    {
        mutex.Close();
        mutex = null;
    }
    if (mutex == null)
    {
        return true;
    }
    return false;
}
進程單實例

 

 

未完待續,下一篇隨筆: EventWaitHandle(Event通知) 

附,Demo : http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip

參見更多:隨筆導讀:同步與異步

相關文章
相關標籤/搜索