首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

並發數據結構:.NET 讀寫鎖演進與最佳實踐

     編輯:關於.NET

多線程讀寫共享資源時,單純互斥鎖過於保守。讀寫鎖允許:多線程並發讀、單線程獨占寫、讀寫互斥。.NET 提供兩代讀寫鎖,差異巨大。

第一代:ReaderWriterLock(不推薦)

.NET 1.1 引入,但官方與 Jeffrey Richter 均強烈批評:

  • 性能極差:獲取讀鎖比 Monitor.Enter 慢 5 倍,寫鎖慢 6 倍。
  • 策略失衡:寫入完成後優先喚醒讀線程,導致寫線程飢餓、數據更新滯後,甚至活鎖。
  • 遞歸開銷大:需為每線程維護計數,嚴重拖慢性能,且不支持異步編程模式(跨邊界獲取/釋放)。
  • 內核對象洩漏:.NET 2.0 前版本存在,進程結束才回收。
  • 升級非原子:UpgradeToWriteLock 先釋放讀鎖再獲寫鎖,窗口期可被其他線程插入修改。

第二代:ReaderWriterLockSlim(推薦)

.NET 3.5 引入,一次性解決上述問題:

  • 性能接近 Monitor:約在 2 倍以內。
  • 寫優先策略:寫操作頻率遠低於讀,優先寫入提升伸縮性。
  • 三種鎖模式:Read(共享)、Write(獨占)、UpgradeableRead(可升級讀,同一時刻僅一線程持有)。
  • 原子升級/降級:持有 UpgradeableRead 時,可決定降級為 Read 或升級為 Write,全程無竞爭窗口、無死鎖風險。

升級/降級模式代碼範例

rwLock.EnterUpgradeableReadLock();
try
{
    if (/* 需更新 */)
    {
        rwLock.EnterWriteLock();
        try { /* 寫入 */ }
        finally { rwLock.ExitWriteLock(); }
    }
    else
    {
        rwLock.EnterReadLock();
        rwLock.ExitUpgradeableReadLock(); // 釋放可升級鎖,允許其他讀者
        try { /* 讀取 */ }
        finally { rwLock.ExitReadLock(); }
    }
}
finally
{
    if (isUpdated) rwLock.ExitUpgradeableReadLock();
}

遞歸策略

  • 默認禁止遞歸(除升級/降級外),連續兩次 EnterReadLock 拋 LockRecursionException。
  • 可通過構造函數啟用 LockRecursionPolicy.SupportsRecursion,但不建議新代碼使用(增加複雜度與死鎖風險)。
  • 永久禁止:持有讀鎖時請求寫鎖(極易死鎖)。

豐富的診斷屬性

IsReadLockHeld、WaitingWriteCount、CurrentReadCount、RecursiveWriteCount 等,便於監控與調試。

Windows SRWLock(Vista+)

內核級輕量讀寫鎖,不支持遞歸、不支持升級/降級,設計目標為無偏向、低開銷。.NET 可通過 P/Invoke 封裝使用:

public sealed class SRWLock
{
    private IntPtr rwLock;
    public SRWLock() { InitializeSRWLock(out rwLock); }
    public void EnterReadLock() { AcquireSRWLockShared(ref rwLock); }
    public void EnterWriteLock() { AcquireSRWLockExclusive(ref rwLock); }
    public void ExitReadLock() { ReleaseSRWLockShared(ref rwLock); }
    public void ExitWriteLock() { ReleaseSRWLockExclusive(ref rwLock); }
    // DllImport 略
}

應用場景:緩存設計

緩存典型場景:大量讀、極少寫。MSDN 經典範例展示 ReaderWriterLockSlim 在字典緩存中的完整用法(含 AddOrUpdate 升級模式)。

極致性能場景可考慮 Lock-Free,但編碼極難、正確性難證。讀寫鎖應用範圍更廣、維護性更好。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved