詳解.NET 同步與非同步 之 Mutex

來源:互聯網
上載者:User
本隨筆續接:.NET 同步與非同步 之 安全執行緒的集合 (十一)

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

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

一、抽象基類 WaitHandle

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

通過上面的資訊,我們可以知道 WaitHandle 繼承自 MarshalByRefObject, 並實現了 IDisposable 介面。

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

在MSND中是這樣描述 MarshalByRefObject 的:

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

看到這裡你也許更迷惑了,我用過它? 用過它的子類? 沒錯,就是用過它的子類,並且還很多。

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

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

看到這裡我們只需要知道 WaitHandle 具有跨應用程式定義域進行通訊的能力就可以了。

二、Mutex(進程同步鎖)

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

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

  Mutex由於需要叫用作業系統資源,因此執行的開銷比Monitor大得多,所以如果僅僅需要在應用程式內部的線程間同步操作,Monitor/lock應當是首選

2、Mutex 的用法

  • WaitOne() /WaitOne(TimeSpan, Boolean)及若干個重載:請求所有權,該調用會一直阻塞到當前 mutex 收到訊號,或直至達到可選的逾時間隔,這幾個方法都不需要提供鎖定對象作為額外參數。

    • 您可以使用 WaitHandle.WaitOne 請求所有權的互斥體的方法。 調用線程受到阻止,直到發生下列情況之一︰

    • 互斥體發出訊號以指示不擁有。 在此情況下, WaitOne 方法將返回 true, ,調用線程的互斥體所有權,並訪問由 mutex 保護的資源。 線程完成後訪問資源,必須調用 ReleaseMutex 方法來釋放 mutex 的所有權。

    • 對調用中指定的逾時間隔 WaitOne 具有方法 millisecondsTimeouttimeout 參數已過。 在此情況下, 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

3、全域和局部的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或者Null 字元串 則相當於建立一個沒有名字的Mutex,當屬於局部Mutex. 而有名字的Mutex當屬於全域Mutex.第三個bool參數、如果已經初始化了互斥體 返回True, 如果互斥體已經存在則返回False. 最後一個參數用於Mutex訪問的安全性控制。

4、用途

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;}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.