標籤:des blog http io ar os 使用 sp on
轉自;http://www.cnblogs.com/lucifer1982/archive/2008/12/07/1349437.html
ReaderWriterLockSlim 類
新的 ReaderWriterLockSlim 類支援三種鎖定模式:Read,Write,UpgradeableRead。這三種模式對應的方法分別是 EnterReadLock,EnterWriteLock,EnterUpgradeableReadLock 。再就是與此對應的 TryEnterReadLock,TryEnterWriteLock,TryEnterUpgradeableReadLock,ExitReadLock,ExitWriteLock,ExitUpgradeableReadLock。Read 和 Writer 鎖定模式比較簡單易懂:Read 模式是典型的共用鎖定定模式,任意數量的線程都可以在該模式下同時獲得鎖;Writer 模式則是互斥模式,在該模式下只允許一個線程進入該鎖。UpgradeableRead 鎖定模式可能對於大多數人來說比較新鮮,但是在資料庫領域卻眾所周知。
這個新的讀寫鎖類效能跟 Monitor 類大致相當,大概在 Monitor 類的 2 倍之內。而且新鎖優先讓寫線程獲得鎖,因為寫操作的頻率遠小於讀操作。通常這會導致更好的延展性。起初,ReaderWriterLockSlim 類在設計時考慮到相當多的情況。比如在早期 CTP 的代碼還提供了PrefersReaders, PrefersWritersAndUpgrades 和 Fifo 等競爭策略。但是這些策略雖然添加起來非常簡單,但是會導致情況非常的複雜。所以 Microsoft 最後決定提供一個能夠在大多數情況下良好工作的簡單模型。
ReaderWriterLockSlim 的更新鎖定
現在讓我們更加深入的討論一下更新模型。UpgradeableRead 鎖定模式允許安全的從 Read 或 Write 模式下更新。還記得先前 ReaderWriterLock 的更新是非原子性,危險的操作嗎(尤其是大多數人根本沒有意識到這點)?現在提供的新讀寫鎖既不會破壞原子性,也不會導致死結。新鎖一次只允許一個線程處在 UpgradeableRead 模式下。
一旦該讀寫鎖處在 UpgradeableRead 模式下,線程就能讀取某些狀態值來決定是否降級到 Read 模式或升級到 Write 模式。注意應當儘可能快的作出這個決定:持有 UpgradeableRead 鎖會強制任何新的讀請求等待,儘管已存在的讀取操作仍然活躍。遺憾的是,CLR 團隊移除了 DowngradeToRead 和 UpgradeToWrite 兩個方法。如果要降級到讀鎖,只要簡單的在 ExitUpgradeableReadLock 方法後緊跟著調用 EnterReadLock 方法即可:這可以讓其他的 Read 和 UpgradeableRead 獲得完成先前應當持有卻被 UpgradeableRead 鎖持有的操作。如果要升級到寫鎖,只要簡單調用 EnterWriteLock 方法即可:這可能要等待,直到不再有任何線程在 Read 模式下持有鎖。不像降級到讀鎖,必須調用 ExitUpgradeableReadLock。在 Write 模式下不必非得調用 ExitUpgradeableReadLock。但是為了形式統一,最好還是調用它。比如下面的代碼:
using System;using System.Linq;using System.Threading;namespace Lucifer.CSharp.Sample{ class Program { private ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(); void Sample() { bool isUpdated = true; rwLock.EnterUpgradeableReadLock(); try { if (/* … 讀取狀態值來決定是否更新 … */) { rwLock.EnterWriteLock(); try { //… 寫入狀態值 … } finally { rwLock.ExitWriteLock(); } } else { rwLock.EnterReadLock(); rwLock.ExitUpgradeableReadLock(); isUpdated = false; try { //… 讀取狀態值 … } finally { rwLock.ExitReadLock(); } } } finally { if (isUpdated) rwLock.ExitUpgradeableReadLock(); } } }}ReaderWriterLockSlim 的遞迴策略
新的讀寫鎖還有一個有意思的特性就是它的遞迴策略。預設情況下,除已提及的降級到讀鎖和升級到寫鎖之外,所有的遞迴請求都不允許。這意味著你不能連續兩次調用 EnterReadLock,其他模式下也類似。如果你這麼做,CLR 將會拋出 LockRecursionException 異常。當然,你可以使用 LockRecursionPolicy.SupportsRecursion 的建構函式參數讓該讀寫鎖支援遞迴鎖定。但不建議對新的開發使用遞迴,因為遞迴會帶來不必要的複雜情況,從而使你的代碼更容易出現死結現象。
有一種特殊的情況永遠也不被允許,無論你採取什麼樣的遞迴策略。這就是當線程持有讀鎖時請求寫鎖。Microsoft 曾經考慮提供這樣的支援,但是這種情況太容易導致死結。所以 Microsoft 最終放棄了這個方案。
此外,這個新的讀寫鎖還提供了很多對應的屬性來確定線程是否在指定模型下持有該鎖。比如 IsReadLockHeld, IsWriteLockHeld 和 IsUpgradeableReadLockHeld 。你也可以通過 WaitingReadCount,WaitingWriteCount 和 WaitingUpgradeCount 等屬性來查看有多少線程正在等待持有特定模式下的鎖。CurrentReadCount 屬性則告知目前有多少並發讀線程。RecursiveReadCount, RecursiveWriteCount 和 RecursiveUpgradeCount 則告知目前線程進入特定模式鎖定狀態下的次數。
小結
這篇文章分析了 .NET 中提供的兩個讀寫鎖類。然而 .NET 3.5 提供的新讀寫鎖 ReaderWriterLockSlim 類消除了 ReaderWriterLock 類存在的主要問題。與 ReaderWriterLock 相比,效能有了極大提高。更新具有原子性,也可以極大避免死結。更有清晰的遞迴策略。在任何情況下,我們都應該使用 ReaderWriterLockSlim 來代替 ReaderWriterLock 類。
並發資料結構 : .NET Framework 中提供的讀寫鎖 ReaderWriterLockSlim 類