
本文主要講解.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底層入門總結內容
如有哪里講得不是很明白或是有錯誤,歡迎指正
如您喜歡的話不妨點個贊收藏一下吧🙂
個人微信