一、前言
本文章匯總c#中常見的鎖,基本都列出了該鎖在微軟官網的文章,一些不常用的鎖也可以參考微軟文章左側的串列,方便溫習回顧,
二、鎖的分類
2.1、用戶模式鎖
1、volatile 關鍵字
volatile 并沒有實作真正的執行緒同步,操作級別停留在變數級別并非原子級別,對于單系統處理器中,變數存盤在主記憶體中,沒有機會被別人修改,但是如果是多處理器,可能就會有問題,因為每個處理器都有單獨的data cache,資料更新不一定立刻被寫回到主存,可能會造成不同步,
參考:valatile 微軟官網文章,
2、Spinlock 旋轉鎖
Spinlock 是內核中提供的一種比較常見的鎖機制,自旋鎖是“原地等待”的方式解決資源沖突的,即,一個執行緒獲取了一個自旋鎖后,另外一個執行緒期望獲取該自旋鎖則獲取不到,只能夠原地“打轉”(忙等待),由于自旋鎖的這個忙等待的特性,注定了它使用場景上的限制 :自旋鎖不應該被長時間的持有(消耗 CPU 資源),
參考:Spinlock 微軟官網文章,
2.2、內核模式鎖
1、事件鎖
自動事件鎖:AutoResetEvent
WaitOne()進入等待,Set()會釋放當前鎖給一個等待執行緒,
var are = new AutoResetEvent(true); are.WaitOne(); //... are.Set();
手動事件鎖:ManualResetEvent
WaitOne()進入等待,Set()會釋放當前鎖給所有等待執行緒,
var mre = new ManualResetEvent(false); mre.WaitOne();//批量攔截,后續的省略號部分是無序執行的, //... mre.Set();//一次釋放給所有等待執行緒
參考:ManuaResetEvent 微軟官網文章,
2、信號量
信號量:Semaphore
信號量可以控制同時通過的執行緒數以及總的執行緒數,
//第一個引數表示同時可以允許的執行緒數,比如1表示每次只允許一個執行緒通過, //第二個是最大值,比如8表示最多有8個執行緒, var semaphore = new Semaphore(1, 8);
參考:Semaphore 微軟官網文章,
3、互斥鎖
互斥鎖:Mutex
Mutex和Monitor很接近,但是沒有Monitor.Pulse,Wait,PulseAll的喚醒功能,他的優點是可以跨行程,可以在同一臺機器甚至遠程機器人的不同行程間共用一個互斥體,
var mutex = new Mutex(); mutex.WaitOne(); //... mutex.ReleaseMutex();
參考:Mutex 微軟官網文章,
4、讀寫鎖
讀寫鎖:ReaderWriterLock
不要使用ReaderWriterLock,該類有問題(死鎖、性能),請使用ReaderWriterLockSlim
.NET Framework有兩個讀取器-撰寫器鎖,ReaderWriterLockSlim以及ReaderWriterLock, 建議對所有新開發的專案使用 ReaderWriterLockSlim, 雖然 ReaderWriterLockSlim 類似于 ReaderWriterLock,但不同之處在于,前者簡化了遞回規則以及鎖狀態的升級和降級規則, ReaderWriterLockSlim 避免了許多潛在的死鎖情況, 另外,ReaderWriterLockSlim 的性能顯著優于 ReaderWriterLock,
參考:ReaderWriterLock 微軟官網文章,
讀寫鎖:ReaderWriterLockSlim
//原始碼摘錄自微軟官網 using System; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; public class SynchronizedCache { private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(); private Dictionary<int, string> innerCache = new Dictionary<int, string>(); public int Count { get { return innerCache.Count; } } public string Read(int key) { cacheLock.EnterReadLock(); try { return innerCache[key]; } finally { cacheLock.ExitReadLock(); } } public void Add(int key, string value) { cacheLock.EnterWriteLock(); try { innerCache.Add(key, value); } finally { cacheLock.ExitWriteLock(); } } public bool AddWithTimeout(int key, string value, int timeout) { if (cacheLock.TryEnterWriteLock(timeout)) { try { innerCache.Add(key, value); } finally { cacheLock.ExitWriteLock(); } return true; } else { return false; } } public AddOrUpdateStatus AddOrUpdate(int key, string value) { cacheLock.EnterUpgradeableReadLock(); try { string result = null; if (innerCache.TryGetValue(key, out result)) { if (result == value) { return AddOrUpdateStatus.Unchanged; } else { cacheLock.EnterWriteLock(); try { innerCache[key] = value; } finally { cacheLock.ExitWriteLock(); } return AddOrUpdateStatus.Updated; } } else { cacheLock.EnterWriteLock(); try { innerCache.Add(key, value); } finally { cacheLock.ExitWriteLock(); } return AddOrUpdateStatus.Added; } } finally { cacheLock.ExitUpgradeableReadLock(); } } public void Delete(int key) { cacheLock.EnterWriteLock(); try { innerCache.Remove(key); } finally { cacheLock.ExitWriteLock(); } } public enum AddOrUpdateStatus { Added, Updated, Unchanged }; ~SynchronizedCache() { if (cacheLock != null) cacheLock.Dispose(); } }ReaderWriterLockSlim示例
參考:ReaderWriterLockSlim 微軟官網文章,
2.3、動態計數鎖
1、動態計數鎖:CountdownEvent
限制執行緒數的一個機制,而且這個也是比較常用的(同屬于信號量的一種),
var cde = new CountdownEvent(10); //重置當前ThreadCount上限 cde.Reset(10); for(int i=0; i<10; i++) { Task.Factory.StartNew(()=> { Thread.Sleep(1000); SubWoker1(); }); } cde.Wait();//相當于Task.WaitAll() cde.Reset(8); for(int i=0; i<8; i++) { Task.Factory.StartNew(()=> { Thread.Sleep(1000); SubWoker2(); }); } cde.Wait();//相當于Task.WaitAll() static void SubWoker1() { //... cde.Signal();//將當前的ThreadCount-1操作, } static void SubWoker2() { //... cde.Signal();//將當前的ThreadCount-1操作, }CountdownEvent示例
參考:CountdownEvent 微軟官網文章,
2、原子操作類:Interlocked
Interlocked類則提供了4種方法進行原子級別的變數操作,Increment , Decrement , Exchange 和CompareExchange ,
a、使用Increment 和Decrement 可以保證對一個整數的加減為一個原子操作,
b、Exchange 方法自動交換指定變數的值,
c、CompareExchange 方法組合了兩個操作:比較兩個值以及根據比較的結果將第三個值存盤在其中一個變數中,
d、比較和交換操作也是按原子操作執行的,Interlocked.CompareExchange(ref a, b, c); 原子操作,a引數和c引數比較, 相等b替換a,不相等不替換,
參考:Interlocked 微軟官網文章,
2.4、監視鎖
1、監視鎖:Monitor
Monitor鎖為操作的代碼塊添加互斥物件,如果A執行緒正在訪問,物件沒有到達臨界區,則B執行緒不會訪問,
參考:Monitor 微軟官網文章,
2、監視鎖:lock
lock鎖可以視為monitor鎖的語法糖,增加了自動釋放機制和例外處理機制,
a、不推薦使用lock(this)的方式作為lock鎖,因為你不確定別的地方是否重新實體了含有lock的物件,
b、不要lock一個字串,
c、不要lock一個外部公開變數,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/534022.html
標籤:C#
上一篇:C#多執行緒之高級篇(上)
