一文帶你了解.Net互斥鎖

本文主要講解.Net基於Threading.Mutex實現互斥鎖
基礎互斥鎖實現
基礎概念:和自旋鎖一樣,作業系統提供的互斥鎖內部有一個數值表示鎖是否已經被獲取,不同的是當獲取鎖失敗的時候,它不會反覆進行重試,而且讓執行緒進入等待狀態,並把執行緒對象添加到鎖關聯的隊列中,另一個執行緒釋放鎖時會檢查隊列中是否有執行緒對象,如果有則通知作業系統喚醒該執行緒,因為獲取鎖的執行緒對象沒有進行運行,即使鎖長時間不釋放也不會消耗CPU資源,但讓執行緒進入等待狀態和從等待狀態喚醒的時間比自旋鎖重試的納秒級時間要長
windows和linux的區別
在windows系統上互斥鎖通過CreateMuteEx函數創建,獲取鎖時將調用WaitForMultipleObjectsEx函數,釋放鎖將調用ReleaseMutex函數,執行緒進入等待狀態和喚醒由系統操作
在Linux上互斥鎖對象由NetCore的內部介面模擬實現,結果包含鎖的狀態值以及等待執行緒隊列,每個託管執行緒都會關聯一個pthread_mutex_t對象和一個pthread_cond_t對象,這兩個對象友pthread類庫提供,獲取鎖失敗執行緒會調價到隊列pthread_cond_wait函數等待,另一個執行緒釋放鎖時看到隊列中有執行緒則調用pthread_cond_signal函數喚醒。
基礎互斥鎖程式碼實現
public static class MutexDemo
{
private static readonly Mutex _lock = new Mutex(false, null);
private static int _counterA = 0;
private static int _counterB = 0;
public static void IncrementCounters()
{
//獲取鎖
_lock.WaitOne();
try
{
++_counterA;
++_counterB;
}
finally
{
//釋放鎖
_lock.ReleaseMutex();
}
}
public static void GetCounters(out int counterA, out int counterB)
{
_lock.WaitOne();
try
{
counterA = _counterA;
counterB = _counterB;
}
finally
{
//釋放鎖
_lock.ReleaseMutex();
}
}
}
互斥鎖(遞歸鎖)
基礎概念:Mutex提供的鎖可重入,已經獲取鎖的執行緒可以再次執行獲取鎖的操作,但釋放鎖的操作也要執行對應的相同次數,可重入的鎖又叫遞歸鎖。
實現原理:遞歸鎖內部使用一個計數器記錄進入次數,同一個執行緒每獲取一次就加1,釋放一次就減1,減1後如果計算器為0就執行真正的釋放操作。遞歸鎖在單個函數中使用沒有意義,一般嵌套在多個函數中
程式碼實現
public static class MutexRecursionDemo
{
private static Mutex _lock = new Mutex(false, null);
private static int _counterA = 0;
private static int _counterB = 0;
public static void IncrementCountersA()
{
//獲取鎖
_lock.WaitOne();
try
{
++_counterA;
}
finally
{
//釋放鎖
_lock.ReleaseMutex();
}
}
public static void IncrementCountersB()
{
//獲取鎖
_lock.WaitOne();
try
{
++_counterB;
}
finally
{
//釋放鎖
_lock.ReleaseMutex();
}
}
public static void IncrementCounters()
{
//獲取鎖
_lock.WaitOne();
try
{
IncrementCountersA();
IncrementCountersB();
}
finally
{
//釋放鎖
_lock.ReleaseMutex();
}
}
public static void GetCounters(out int counterA, out int counterB)
{
_lock.WaitOne();
try
{
counterA = _counterA;
counterB = _counterB;
}
finally
{
//釋放鎖
_lock.ReleaseMutex();
}
}
}
互斥鎖(跨進程使用)
基礎概念:Mutex支援誇進程使用,創建是通過構造函數的第二個參數name傳入名稱,名稱以Walterlv.Mutex開始時同一個用戶的進程共享擁有此名稱的鎖,如果一個進程中獲取了鎖,那麼在釋放該鎖前另一個進程獲取同樣名稱的鎖需要等待,如果進程獲取了鎖,但是在退出之前沒有調用釋放鎖的方法,那麼鎖會被自動釋放,其他當前正在等待鎖的京城會受到AbandonedMuteException異常。
linux實現方式是通過臨時文件的方式實現
實現程式碼
public static class MutexDemo
{
private static Mutex _lock = new Mutex(false, @"Walterlv.Mutex");
private static int _counterA = 0;
private static int _counterB = 0;
public static void IncrementCounters()
{
//獲取鎖
_lock.WaitOne();
try
{
++_counterA;
++_counterB;
}
finally
{
//釋放鎖
_lock.ReleaseMutex();
}
}
public static void GetCounters(out int counterA, out int counterB)
{
_lock.WaitOne();
try
{
counterA = _counterA;
counterB = _counterB;
}
finally
{
//釋放鎖
_lock.ReleaseMutex();
}
}
}
以上程式碼只需要複製一份,在多個程式中啟動,調用MutexDemo.IncrementCounters()則可以看到效果
本文基於.Net Core底層入門總結內容
如有哪裡講得不是很明白或是有錯誤,歡迎指正
如您喜歡的話不妨點個贊收藏一下吧🙂
個人微信


