<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C# 鎖機制全景與高效實踐:從 Monitor 到 .NET 9 全新 Lock

      引言:線程安全與鎖的基本概念

      線程安全

      在多線程編程中,保障共享資源的安全訪問依賴于有效的線程同步機制。理解并處理好以下兩個核心概念至關重要:

      • 線程安全:指某個類、方法或數據結構能夠在被多個線程同時訪問或修改時,依然保持內部狀態的一致性,并產生預期的結果。這通常意味著需要對共享狀態(如全局變量、靜態變量或對象實例字段)的并發訪問進行有效管控,防止數據損壞或不一致性。
      • 競態條件 (Race Condition): 是一種典型的并發缺陷。當多個線程在缺乏適當同步機制的情況下,無序地、競爭性地訪問或修改共享資源時,程序執行結果變得依賴于無法預測的線程調度時序(即執行順序)。這種不確定性常常會導致數據錯誤、程序崩潰或行為異常。競態條件是線程安全缺失的直接體現。

      鎖的基本概念

      • 鎖的本質:鎖是一種同步工具,用于確保共享資源的互斥訪問(一次只有一個線程使用)。當一個線程獲得鎖并執行被保護的代碼段(臨界區)時,其他試圖獲取同一鎖的線程會被阻塞或等待,直到鎖被釋放。
      • 鎖的目標:在保證正確性的前提下,最大化并發度和系統吞吐量,最小化延遲。
      • 鎖的代價:
        • 阻塞開銷:操作系統調度上下文切換的成本。
        • 自旋開銷:忙等待消耗CPU周期。
        • 死鎖風險:線程因相互等待對方釋放鎖而永久僵持。
        • 優先級反轉:低優先級線程持有高優先級線程需要的鎖。
        • 復雜性:使用不當可能導致程序難以理解和調試。
        • 選擇鎖的依據:臨界區大小、等待時間長短、競爭激烈程度、讀/寫比例、進程邊界、公平性要求等。

      1. Monitor

      原理

      Monitor類提供了一種互斥鎖機制,確保同一時間只有一個線程可以訪問臨界區。它是C#中lock語句的基礎,通過Monitor.EnterMonitor.Exit實現鎖的獲取和釋放。

      基于對象的內部 SyncBlock 索引關聯的一個系統鎖對象。每個.NET對象在堆上分配時,都有一個關聯的 Sync Block Index (SBI)。當首次對這個對象使用 lock 時,SBI 被分配并指向操作系統內核中的一個真正的鎖對象(比如 Windows 的 CRITICAL_SECTION)。

      當鎖已被占用時,后續請求的線程會進入內核等待狀態,發生上下文切換。

      Monitor.Wait(object obj), Monitor.Pulse(object obj), Monitor.PulseAll(object obj) 提供了在鎖內等待特定條件成立的能力(類似 ConditionVariable),可用于構建生產者-消費者模式等。

      操作方式

      lock語句是使用Monitor的簡便方式:

      private readonly object _lock = new object();
      
      lock (_lock)
      {
          // 臨界區代碼
      }

      等價于:

      Monitor.Enter(_lock);
      try
      {
          // 臨界區代碼
      }
      finally
      {
          Monitor.Exit(_lock);
      }

      應用場景

      • 保護共享變量或非線程安全的集合
      • 確保單一線程修改資源,如更新計數器或列表
      • 需要簡單互斥的臨界區
      • 臨界區執行時間相對較長(大于上下文切換開銷)
      • 鎖競爭不是極端激烈

      最佳實踐

      • 使用私有對象(如private readonly object _lock = new object();)進行鎖定,避免死鎖。
      • 保持臨界區盡可能短,減少鎖競爭。
      • 避免鎖定公共對象或類型(如typeof(MyClass)),因為其他代碼可能也會鎖定它們。
      • 不要在鎖內調用不可控的外部代碼,可能導致死鎖。

      優點

      • 使用簡單,lock語句語法直觀。
      • 對于短臨界區效率較高。
      • Monitor 鎖是可重入(Reentrancy)的。同一個線程可以多次獲得同一個鎖對象上的鎖(進入嵌套的 lock 塊)。計數器會增加,只有等計數器歸零時鎖才會被釋放。

      缺點

      • 可能導致死鎖,如果鎖使用不當。Monitor.TryEnter(object obj, int timeoutMilliseconds) 允許設置等待超時,是避免死鎖的重要手段。
      • 不支持多讀單寫場景。
      • .NET 的 Monitor 鎖是非公平的(Windows CLR 實現)。當鎖釋放時,操作系統從等待隊列中選擇下一個喚醒的線程是不確定的,不一定是最早等待的那個(這有助于提高吞吐量,但可能導致某些線程“饑餓”)。

      2. System.Threading.Lock

      原理

      System.Threading.Lock是.NET 9(C# 13)引入的新同步原語,旨在提供比Monitor更高效的互斥鎖機制。它通過EnterScope方法支持using語句,確保鎖自動釋放,降低死鎖風險。

      操作方式

      直接使用:

      private readonly Lock _lock = new Lock();
      
      using (_lock.EnterScope())
      {
          // 臨界區代碼
      }

      或在C# 13及以上版本中使用lock語句:

      lock (_lock)
      {
          // 臨界區代碼
      }

      應用場景

      • Monitor類似,用于保護共享資源。
      • 適用于需要高性能的場景,如高并發系統。

      最佳實踐

      • 使用私有Lock實例。
      • 利用using語句確保鎖自動釋放。
      • 避免將Lock對象轉換為object或其他類型,以防止編譯器警告。

      優點

      • 性能比Monitor高約25%。
      | Method                   | Mean      | Error    | StdDev   | Ratio | Gen0   | Allocated | Alloc Ratio |
      |------------------------- |----------:|---------:|---------:|------:|-------:|----------:|------------:|
      | CountTo1000WithLock      | 107.22 us | 1.561 us | 1.460 us |  1.00 | 0.1221 |   1.06 KB |        1.00 |
      | CountTo1000WithLockClass |  75.73 us | 0.884 us | 0.827 us |  0.71 | 0.1221 |   1.05 KB |        0.99 |
      • 使用Dispose模式自動釋放鎖,降低死鎖風險。
      • lock語句無縫集成,語法簡潔。

      缺點

      • 需要.NET 9或更高版本。
      • 開發者對其熟悉度較低。

      3. Mutex

      原理

      • Mutex(互斥鎖)是一種支持進程間同步的互斥鎖機制,確保只有一個線程或進程訪問共享資源。
      • 可以通過命名互斥鎖實現跨進程同步。
      • 比 Monitor/lock 重得多(涉及系統調用)。
      • 支持安全訪問系統資源(如文件、硬件設備句柄)。

      操作方式

      private static Mutex _mutex = new Mutex();
      
      _mutex.WaitOne();
      // 臨界區代碼
      _mutex.ReleaseMutex();

      應用場景

      • 跨進程同步,如確保應用程序的單一實例運行。
      • 保護共享資源,如文件或數據庫。

      最佳實踐

      • 使用命名互斥鎖(如new Mutex(false, "MyAppMutex"))進行進程間同步。
      • 盡快釋放互斥鎖,減少阻塞時間。

      注意

      • 重入性:命名 Mutex 默認是可重入的(同一個線程)。匿名(未命名)Mutex 在 .NET Framework 默認可重入,在 .NET Core+ 中默認為 .NoRecursion 行為。
      • 自動釋放:如果持有 Mutex 的線程終止(例如崩潰),操作系統會自動釋放鎖(這可能導致程序邏輯錯誤),并且下一個等待的線程可能接收到 AbandonedMutexException。

      優點

      • 支持進程間同步。
      • 提供可靠的互斥訪問。

      缺點

      • 由于涉及內核模式轉換,性能較低。
      • 開銷較大,不適合高頻短臨界區。

      4. SpinLock

      原理

      SpinLock是一種互斥鎖,線程在嘗試獲取鎖時會通過自旋(循環檢查)等待鎖可用,適用于極短的臨界區。

      操作方式

      private SpinLock _spinLock = new SpinLock();
      
      bool lockTaken = false;
      try
      {
          _spinLock.Enter(ref lockTaken);
          // 臨界區代碼
      }
      finally
      {
          if (lockTaken)
          {
              _spinLock.Exit();
          }
      }

      應用場景

      • 極短的臨界區,鎖持有時間短于上下文切換成本。
      • 高并發場景,鎖競爭頻繁但持續時間短。

      最佳實踐

      • 僅用于極短臨界區。
      • 避免在低競爭或長臨界區場景中使用。

      優點

      • 對于短臨界區開銷低。
      • 無上下文切換。

      缺點

      • 如果鎖持有時間長,會浪費CPU周期。
      • 不適合長臨界區。

      5. ReaderWriterLockSlim

      原理

      ReaderWriterLockSlim允許多個線程同時讀取資源,但寫操作互斥,且寫時不允許讀操作,適合讀多寫少的場景。

      有幾種不同的鎖定模式:

      • 讀取鎖 (Read Lock):共享模式,允許多個線程同時持有。
      • 寫入鎖 (Write Lock):獨占模式,一旦持有,排斥所有讀取鎖和其他寫入鎖。
      • 可升級讀取鎖 (Upgradeable Read Lock):一種特殊模式,允許一個讀取線程在持有讀鎖的同時,后續有需要時可以原子性地升級 (Upgrade)為寫入鎖(避免先釋放讀鎖再嘗試拿寫鎖過程中出現競態或死鎖)

      操作方式

      private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
      
      public string ReadData()
      {
          _rwLock.EnterReadLock(); // 獲取讀鎖
          try
          {
              // 安全讀取共享數據
              return _cachedData;
          }
          finally
          {
              _rwLock.ExitReadLock(); // 釋放讀鎖
          }
      }
      
      public void UpdateData(string newData)
      {
          _rwLock.EnterWriteLock(); // 獲取寫鎖
          try
          {
              // 安全更新共享數據
              _cachedData = newData;
          }
          finally
          {
              _rwLock.ExitWriteLock(); // 釋放寫鎖
          }
      }
      
      // 使用可升級鎖 (避免“寫者饑餓”風險):
      public void UpdateIfCondition(string newData, Func<bool> condition)
      {
          _rwLock.EnterUpgradeableReadLock(); // 獲取可升級讀鎖
          try
          {
              if (condition())
              {
                  _rwLock.EnterWriteLock(); // 升級為寫鎖
                  try
                  {
                      // 安全更新共享數據
                      _cachedData = newData;
                  }
                  finally
                  {
                      _rwLock.ExitWriteLock(); // 降級回可升級讀鎖
                  }
              }
          }
          finally
          {
              _rwLock.ExitUpgradeableReadLock(); // 釋放鎖
          }
      }

      應用場景

      • 讀操作頻繁、寫操作較少的場景,如緩存系統。

      最佳實踐

      • 確保寫操作快速,減少讀線程阻塞。
      • 避免長時間持有寫鎖,防止寫者饑餓。

      注意

      • ReaderWriterLockSlim 性能更好,語義更清晰,設計更合理。強烈建議總是使用 ReaderWriterLockSlim 而不是 ReaderWriterLock。
      • 性能特征:在純讀場景下并發度接近無鎖;寫操作開銷比普通互斥鎖略高(需要管理讀寫狀態轉換);升級操作開銷適中。
      • 公平性與策略:提供了構造參數 LockRecursionPolicy.NoRecursion / .SupportsRecursion 和 ReaderWriterLockSlim(lockRecursionPolicy) 來控制遞歸行為。也涉及公平性問題(如讀者優先或寫者優先,ReaderWriterLockSlim 有機制防止寫者餓死)。

      優點

      • 允許多個線程同時讀取,提高性能。
      • 適合讀多寫少場景。

      缺點

      • 使用復雜,需管理讀寫鎖狀態。不恰當地嵌套獲取不同類型的鎖(特別是嘗試升級鎖失敗時等待其他鎖)會導致死鎖。
      • 可能導致寫者饑餓。

      6. Semaphore 和 SemaphoreSlim

      原理

      • Semaphore控制對資源池的并發訪問,限制同時訪問的線程數。
      • Semaphore:內核模式,支持跨進程、命名。
      • SemaphoreSlim:輕量級用戶模式實現(必要時退化到內核),僅進程內有效,性能開銷遠小于 Semaphore。絕大多數進程內場景應優先使用 SemaphoreSlim。
      • SemaphoreSlim 默認使用公平隊列(FIFO),有助于防止饑餓。Semaphore 的公平性由操作系統決定。

      操作方式

      private Semaphore _semaphore = new Semaphore(3, 3); // 初始和最大計數
      
      //WaitOne/WaitAsync:嘗試獲取一個令牌(信號)。若無可用令牌則阻塞/異步等待
      _semaphore.WaitOne();
      // Release:釋放一個令牌
      _semaphore.Release();

      SemaphoreSlim使用方式類似。

      應用場景

      • 限制并發訪問特定資源的數量(API調用限流、連接池控制、異步任務并發度控制)。

      最佳實踐

      • 使用Semaphore進行進程間同步,SemaphoreSlim用于進程內。
      • 設置合理的初始和最大計數。

      優點

      • 靈活控制并發級別。
      • SemaphoreSlim性能較高。

      缺點

      • 使用較復雜。
      • 可能導致死鎖。

      7. EventWaitHandle、AutoResetEvent、ManualResetEvent、ManualResetEventSlim

      原理

      事件用于線程間信號傳遞。AutoResetEvent在信號一個等待線程后自動重置;ManualResetEvent保持信號狀態直到手動重置;ManualResetEventSlim是輕量級版本。

      操作方式

      AutoResetEvent示例:

      private AutoResetEvent _event = new AutoResetEvent(false);
      
      _event.WaitOne(); // 等待信號
      // 執行操作
      
      _event.Set(); // 發送信號

      ManualResetEvent示例:

      private ManualResetEvent _event = new ManualResetEvent(false);
      
      _event.WaitOne(); // 等待信號
      // 執行操作
      
      _event.Set(); // 發送信號
      _event.Reset(); // 重置事件

      應用場景

      • 生產者-消費者模式。
      • 等待特定任務完成。
      • 啟動/停止信號廣播、一次性初始化完成指示。

      最佳實踐

      • 使用AutoResetEvent進行一對一信號傳遞。
      • 使用ManualResetEvent廣播信號給多個線程。

      優點

      • 提供簡單的信號傳遞機制。

      缺點

      • 狀態管理復雜,尤其是ManualResetEvent。

      8. CountdownEvent

      原理

      初始化一個計數(N)。線程調用 Signal() 來遞減計數。當計數達到0時,所有在該對象上 Wait() 的線程被釋放。適用于“N個任務完成后繼續”的場景。

      操作方式

      private CountdownEvent _countdown = new CountdownEvent(3);
      
      _countdown.Wait(); // 等待計數歸零
      // 執行操作
      
      _countdown.Signal(); // 減少計數

      應用場景

      • 主線程等待一組分散操作的完成,模擬部分 Task.WaitAll 效果但有更多控制(可在操作執行過程中動態調整計數)。

      最佳實踐

      • 設置正確的初始計數。
      • 確保所有信號都發送,避免死鎖。

      優點

      • 便于等待多個事件。

      缺點

      • 僅限于計數場景。

      9. Barrier

      原理

      允許多個線程分階段執行任務,并確保所有參與線程在一個共同的屏障點(Phase)同步匯合(都到達后)才能繼續下一階段。

      操作方式

      private Barrier _barrier = new Barrier(3);
      
      _barrier.SignalAndWait(); // 信號并等待其他線程
      // 繼續執行

      應用場景

      • 并行算法中協調多個線程的階段,如分治算法、復雜數據并行流水線處理。

      最佳實踐

      • 確保所有參與者調用SignalAndWait。

      優點

      • 協調多線程分階段執行。

      缺點

      • 設置復雜,需確保所有線程參與。

      10. SpinWait

      原理

      SpinWait通過自旋等待條件成立,適合短時間等待。

      操作方式

      SpinWait.SpinUntil(() => someCondition);

      應用場景

      • 短時間等待條件成立,如檢查標志位。

      最佳實踐

      • 用于預期很快滿足的條件。
      • 避免長時間自旋。

      優點

      • 避免上下文切換。

      缺點

      • 長時間等待浪費CPU資源。

      11. 無鎖替代

      • 不可變性 (Immutability):一旦創建對象就不可修改。避免了修改引起的同步需求(readonly 字段,記錄類型 record)。

      • 線程本地存儲 (Thread-Local Storage - TLS):ThreadStaticAttribute, AsyncLocal 變量,ThreadLocal。每個線程使用自己獨立的數據副本(適用性有限)。

      • Interlocked 類:提供對簡單類型(int, long, IntPtr, float, double, object 引用)執行原子操作的靜態方法(Increment, Decrement, Add, Exchange, CompareExchange)。是最輕量級的“鎖”,基于 CPU 的原子指令實現,性能極高,無鎖開銷。

        private int _counter = 0;
        public void IncrementSafely()
        {
            Interlocked.Increment(ref _counter); // 原子+1
        }
        public void SetIfEqual(int newValue, int expected)
        {
            Interlocked.CompareExchange(ref _counter, newValue, expected); // CAS
        }
      • 基于任務的異步模式 (TAP) 與 Task:

        • Channel (System.Threading.Channels):.NET Core 2.1+ 引入。高性能、無鎖/有界可選的生產者-消費者隊列替代方案(取代 BlockingCollection 和無鎖隊列手動實現)。支持單/多生產者、單/多消費者。是編寫異步管道、處理背壓 (Backpressure) 的首選。
        var channel = Channel.CreateUnbounded<T>();
        // 生產者
        await channel.Writer.WriteAsync(item);
        // 消費者
        while (await channel.Reader.WaitToReadAsync())
            while (channel.Reader.TryRead(out var item)) { ... }
        • ValueTask / IValueTaskSource:Task 的輕量級替代(減少了堆分配),尤其在同步完成路徑上優化顯著。
      • Immutable Collections (System.Collections.Immutable):提供線程安全的不可變集合,通過原子替換整個集合引用來“修改”數據。讀操作非常高效(無需鎖),寫操作創建新集合,適合讀遠多于寫的共享數據。

      • 專為并發訪問設計的內置集合:

        • ConcurrentDictionary<TKey, TValue>:高效、低鎖競爭、可并行的字典。
        • ConcurrentQueue / ConcurrentStack:先進先出(FIFO) / 后進先出(LIFO)隊列,基于CAS實現,避免鎖爭用。
        • BlockingCollection:有界/無界生產者-消費者隊列(底層使用 ConcurrentQueue 等),提供 Take() 阻塞語義(Channel 通常是更好的異步選擇)。支持優雅取消和完成通知。

      12. 結語

      選擇合適的同步原語取決于應用程序需求,如是否需要進程間同步、讀寫分離或高性能。System.Threading.Lock是C# 13 中的新選擇,性能優于Monitor,適合大多數互斥場景。開發者應根據場景權衡性能、復雜性和功能,確保線程安全的同時避免死鎖和性能瓶頸。

      13. 附件表格對比

      同步原語
      互斥性
      允許多讀
      進程間支持
      性能
      示例用例
      是否支持可重入
      Monitor
      保護共享變量
      System.Threading.Lock
      極高
      高性能互斥鎖
      Mutex
      進程間同步
      SpinLock
      極高
      極短臨界區
      ReaderWriterLockSlim
      是(寫)
      讀多寫少資源
      Semaphore
      限制并發訪問
      SemaphoreSlim
      進程內并發控制
      EventWaitHandle
      線程/進程間信號傳遞
      ManualResetEventSlim
      進程內信號傳遞
      CountdownEvent
      等待多個信號
      Barrier
      分階段線程執行
      Interlocked
      極高
      原子操作
      SpinWait
      短時間自旋等待
      ?

      由于資料驗證范圍太廣,難免會有遺漏,如果上述表格內的內容有問題,請在評論區告訴我

      posted @ 2025-06-12 10:19  AI·NET極客圈  閱讀(3934)  評論(8)    收藏  舉報
      主站蜘蛛池模板: 美女爽到高潮嗷嗷嗷叫免费网站| 国产综合色在线精品| 永久免费在线观看蜜桃视频| 成人午夜福利免费专区无码| 熟女女同亚洲女同中文字幕| 人妻丰满熟妇无码区免费| 亚洲成人网在线观看| 精品黑人一区二区三区| 亚洲av成人三区国产精品| 亚洲午夜成人精品电影在线观看| 亚洲精品一区二区口爆| 亚洲成人av在线系列| 黄色亚洲一区二区三区四区| 四虎成人在线观看免费| 四虎永久播放地址免费| 欧美大屁股xxxx高跟欧美黑人| 国产精自产拍久久久久久蜜| 中美日韩在线一区黄色大片| 人人妻人人妻人人片av| 久久久久国产精品熟女影院| 亚洲国产99精品国自产拍| 久久99日韩国产精品久久99| 国产日韩一区二区天美麻豆| 777米奇影视第四色| 久久国产乱子伦免费精品无码| 大香网伊人久久综合网2020| 色偷一区国产精品| 国产对白老熟女正在播放| 中文在线最新版天堂| 69天堂人成无码免费视频| 亚洲精品第一区二区三区| 欧美videos粗暴| 亚洲国产精品无码一区二区三区 | 亚洲国产精品久久久天堂麻豆宅男 | 茄子视频国产在线观看| 最新的国产成人精品2022| 四虎国产精品永久免费网址| 国内精品久久久久电影院| 国产午夜福利视频合集| 中文字幕亚洲制服在线看| 在线一区二区中文字幕|