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

多線程入門系列(八):Monitor 管程同步機制詳解

     編輯:關於C#

Monitor 核心概念

Monitor 是 .NET 提供的同步基礎設施,lock 關鍵字編譯後即為 Monitor.Enter/Exit。Monitor 提供更精細的控制:

  • Enter/Exit:基本互斥鎖
  • TryEnter:嘗試取得鎖,可設超時,不阻塞
  • Wait/Pulse/PulseAll:條件變數機制,實現生產者-消費者模式

關鍵方法總覽

方法說明
Enter(object)取得物件鎖,阻塞至成功
TryEnter(object)嘗試取得鎖,立即返回 bool
TryEnter(object, TimeSpan)帶超時嘗試取得鎖
Exit(object)釋放鎖
Wait(object)釋放鎖並進入等待隊列
Wait(object, TimeSpan)帶超時等待
Pulse(object)喚醒一個等待線程
PulseAll(object)喚醒所有等待線程

基本互斥用法(等同 lock)

object syncObj = new object();

Monitor.Enter(syncObj);
try
{
    // 臨界區
}
finally
{
    Monitor.Exit(syncObj);
}

// 等同於:
lock (syncObj) { /* 臨界區 */ }

TryEnter 非阻塞嘗試

if (Monitor.TryEnter(syncObj, TimeSpan.FromSeconds(2)))
{
    try { /* 臨界區 */ }
    finally { Monitor.Exit(syncObj); }
}
else
{
    Console.WriteLine("取得鎖超時,放棄操作");
}

Wait/Pulse 生產者-消費者完整範例

using System;
using System.Collections.Generic;
using System.Threading;

public class BoundedBuffer<T>
{
    private readonly Queue<T> queue = new Queue<T>();
    private readonly int capacity;
    private readonly object sync = new object();
    
    public BoundedBuffer(int capacity) { this.capacity = capacity; }
    
    public void Produce(T item)
    {
        lock (sync)
        {
            while (queue.Count == capacity)
                Monitor.Wait(sync); // 滿了等待
            
            queue.Enqueue(item);
            Monitor.Pulse(sync); // 通知消費者
        }
    }
    
    public T Consume()
    {
        lock (sync)
        {
            while (queue.Count == 0)
                Monitor.Wait(sync); // 空了等待
            
            T item = queue.Dequeue();
            Monitor.Pulse(sync); // 通知生產者
            return item;
        }
    }
}

// 使用範例
class Program
{
    static BoundedBuffer<int> buffer = new BoundedBuffer<int>(5);
    
    static void Main()
    {
        new Thread(Producer).Start();
        new Thread(Consumer).Start();
        Thread.Sleep(5000);
    }
    
    static void Producer()
    {
        for (int i = 0; i < 20; i++)
        {
            buffer.Produce(i);
            Console.WriteLine("生產: {0}", i);
            Thread.Sleep(100);
        }
    }
    
    static void Consumer()
    {
        for (int i = 0; i < 20; i++)
        {
            int item = buffer.Consume();
            Console.WriteLine("消費: {0}", item);
            Thread.Sleep(150);
        }
    }
}

Wait 運作細節

  1. 釋放鎖
  2. 進入物件的等待隊列
  3. 阻塞直到被 Pulse 或超時
  4. 被喚醒後,重新競爭鎖
  5. 取得鎖後從 Wait 返回

關鍵:Wait 必須在 lock/Enter 保護下呼叫,否則拋出 SynchronizationLockException。

Monitor vs lock 選擇指南

場景建議
簡單互斥lock(語法簡潔、自動 finally)
需嘗試取得鎖/超時Monitor.TryEnter
條件同步/生產者消費者Monitor.Wait/Pulse
需在不同方法間釋放/取得鎖Monitor.Enter/Exit 手動控制

圖示說明

(原文包含六張圖片,展示 Monitor 方法結構、Wait/Pulse 狀態轉換、生產者消費者時序圖、鎖升級等)

Monitor 方法總覽 Wait/Pulse 狀態機 生產者消費者時序 1 生產者消費者時序 2 Monitor 進階用法 Monitor 與 lock 對比
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved