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

C# 多執行緒機制探索(7):Monitor 監視器模式實現生產者消費者模式完整實戰

     編輯:關於C語言

一、為什麼需要 Monitor?

lock 只能同步程式碼區塊,無法表達「等待特定條件」的語意。Monitor 提供條件變數機制:Wait 釋放鎖並進入等待隊列,Pulse/PulseAll 唤醒等待者。適用於生產者-消費者、讀寫鎖、資源池等需條件同步的場景。

二、Monitor 核心方法

三、Cell 共享資料物件:雙緩衝旗標同步


public class Cell
{
    int _cellContents;
    bool _readerFlag; // true = 可讀/已生產, false = 可寫/待生產

    public int ReadFromCell()
    {
        lock (this)
        {
            if (!_readerFlag) // 尚未生產
            {
                try { Monitor.Wait(this); }
                catch (SynchronizationLockException) { }
                catch (ThreadInterruptedException) { }
            }
            Console.WriteLine($"Consume: {_cellContents}");
            _readerFlag = false; // 標記已消費
            Monitor.Pulse(this); // 通知生產者可生產
        }
        return _cellContents;
    }

    public void WriteToCell(int n)
    {
        lock (this)
        {
            if (_readerFlag) // 尚未消費
            {
                try { Monitor.Wait(this); }
                catch (SynchronizationLockException) { }
                catch (ThreadInterruptedException) { }
            }
            _cellContents = n;
            Console.WriteLine($"Produce: {_cellContents}");
            _readerFlag = true; // 標記已生產
            Monitor.Pulse(this); // 通知消費者可消費
        }
    }
}

四、生產者與消費者類別


public class CellProd
{
    readonly Cell _cell;
    readonly int _quantity;
    public CellProd(Cell cell, int quantity) { _cell = cell; _quantity = quantity; }
    public void ThreadRun()
    {
        for (int i = 1; i <= _quantity; i++)
            _cell.WriteToCell(i);
    }
}

public class CellCons
{
    readonly Cell _cell;
    readonly int _quantity;
    public CellCons(Cell cell, int quantity) { _cell = cell; _quantity = quantity; }
    public void ThreadRun()
    {
        for (int i = 1; i <= _quantity; i++)
            _cell.ReadFromCell();
    }
}

五、主程式啟動與同步


public class MonitorSample
{
    public static void Main()
    {
        int result = 0;
        var cell = new Cell();
        var prod = new CellProd(cell, 20);
        var cons = new CellCons(cell, 20);

        var producer = new Thread(prod.ThreadRun);
        var consumer = new Thread(cons.ThreadRun);

        try
        {
            producer.Start();
            consumer.Start();
            producer.Join();
            consumer.Join();
            Console.ReadLine();
        }
        catch (ThreadStateException e) { Console.WriteLine(e); result = 1; }
        catch (ThreadInterruptedException e) { Console.WriteLine(e); result = 1; }

        Environment.ExitCode = result;
    }
}

六、執行結果與流程分析


Produce: 1
Consume: 1
Produce: 2
Consume: 2
...
Produce: 20
Consume: 20
  1. 生產者取得鎖,檢查 _readerFlag=false,寫入 1,設 true,Pulse
  2. 消費者取得鎖,檢查 _readerFlag=true,讀取 1,設 false,Pulse
  3. 交替進行,嚴格 1:1 對應

七、關鍵設計細節

方法說明
Enter(object)取得物件鎖 (相當於 lock 進入)
Exit(object)釋放物件鎖 (相當於 lock 退出)
Wait(object)釋放鎖並進入等待隊列,被 Pulse 唤醒後重新取得鎖
Wait(object, timeout)帶逾時等待
Pulse(object)喚醒等待隊列中第一個執行緒
PulseAll(object)喚醒等待隊列中所有執行緒
TryEnter(object)嘗試取得鎖,立即返回成否
細節作用
lock(this) 外層確保 Wait/Pulse 與旗標檢查在同一臨界區
_readerFlag 雙緩衝單緩衝無法區分「空」與「滿」狀態
Monitor.Wait 釋放鎖避免死結,允許另一方進入
Pulse 單一喚醒只有一個對方,PulseAll 會造成虛假喚醒
例外處理SynchronizationLockException (非同步區呼叫 Wait) ThreadInterruptedException (等待中被中斷)

八、Monitor vs lock vs Semaphore 比較

特性lockMonitorSemaphore/SemaphoreSlim
條件等待無Wait/Pulse無 (計數信號)
語法糖是否否
跨進程否否具名 Semaphore 可跨進程
非同步支援無無SemaphoreSlim.WaitAsync

總結

Monitor 以物件鎖 + 條件變數模式實現精細的執行緒協作。生產者-消費者模式展示 Wait 釋放鎖等待、Pulse 單點喚醒的經典交互模式。掌握 Monitor 可構建資源池、背壓控制、多階段管線等進階同步結構。現代替代方案:BlockingCollection<T> (內建生產消費)、Channels (非同步管線)、SemaphoreSlim (非同步信號)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved