跳转到内容

C Sharp Monitor 类

来自代码酷

C# Monitor类[编辑 | 编辑源代码]

Monitor类是C#中用于线程同步的核心类之一,属于System.Threading命名空间。它提供了一种机制,允许线程在访问共享资源时进行互斥锁定,从而避免竞态条件(Race Condition)和数据不一致问题。Monitor类是基于临界区(Critical Section)的概念实现的,确保同一时间只有一个线程可以执行特定的代码块。

概述[编辑 | 编辑源代码]

Monitor类通过EnterExit方法实现锁定和解锁操作,通常与lock关键字(语法糖)结合使用。其核心功能包括:

  • 互斥访问:确保共享资源在同一时间仅被一个线程访问。
  • 线程等待与通知:通过WaitPulsePulseAll方法实现线程间的协作。

基本用法[编辑 | 编辑源代码]

使用 lock 关键字[编辑 | 编辑源代码]

C#中的`lock`关键字是Monitor类的简化写法。以下示例展示如何通过`lock`保护共享资源:

using System;
using System.Threading;

class Program
{
    private static readonly object _lock = new object();
    private static int _counter = 0;

    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            new Thread(IncrementCounter).Start();
        }
        Thread.Sleep(1000);
        Console.WriteLine($"Final Counter: {_counter}");
    }

    static void IncrementCounter()
    {
        lock (_lock)
        {
            _counter++;
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: Counter = {_counter}");
        }
    }
}

输出示例:

Thread 3: Counter = 1
Thread 4: Counter = 2
Thread 5: Counter = 3
Thread 6: Counter = 4
Thread 7: Counter = 5
Final Counter: 5

直接使用 Monitor 类[编辑 | 编辑源代码]

等效的Monitor实现如下:

static void IncrementCounter()
{
    Monitor.Enter(_lock);
    try
    {
        _counter++;
        Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: Counter = {_counter}");
    }
    finally
    {
        Monitor.Exit(_lock);
    }
}

关键点:

  • 必须使用`try-finally`确保锁被释放。
  • 若未释放锁会导致死锁

线程协作:Wait 和 Pulse[编辑 | 编辑源代码]

Monitor类支持更复杂的线程交互模式。以下案例模拟生产者-消费者问题:

class Buffer
{
    private readonly object _lock = new object();
    private Queue<int> _queue = new Queue<int>();
    private const int MaxSize = 3;

    public void Produce(int value)
    {
        Monitor.Enter(_lock);
        try
        {
            while (_queue.Count >= MaxSize)
            {
                Monitor.Wait(_lock); // 释放锁并等待
            }
            _queue.Enqueue(value);
            Console.WriteLine($"Produced: {value}");
            Monitor.Pulse(_lock); // 通知等待线程
        }
        finally
        {
            Monitor.Exit(_lock);
        }
    }

    public int Consume()
    {
        Monitor.Enter(_lock);
        try
        {
            while (_queue.Count == 0)
            {
                Monitor.Wait(_lock);
            }
            int value = _queue.Dequeue();
            Console.WriteLine($"Consumed: {value}");
            Monitor.Pulse(_lock);
            return value;
        }
        finally
        {
            Monitor.Exit(_lock);
        }
    }
}

执行流程图:

sequenceDiagram participant Producer participant Buffer participant Consumer Producer->>Buffer: Produce(1) Buffer->>Consumer: Pulse() Consumer->>Buffer: Consume() Buffer->>Producer: Pulse()

注意事项[编辑 | 编辑源代码]

1. 锁对象选择:应使用`private readonly object`作为锁对象,避免使用值类型或`this`。 2. 死锁风险:确保锁在所有路径(包括异常)下都能释放。 3. 性能影响:频繁的锁竞争会降低并发性能。

实际应用场景[编辑 | 编辑源代码]

  • 数据库连接池:管理有限连接的分配。
  • 日志系统:避免多线程写入日志文件时的冲突。
  • 缓存更新:确保缓存数据的原子性更新。

数学原理[编辑 | 编辑源代码]

Monitor的实现基于Dijkstra信号量(Semaphore)理论,其等待队列模型可表示为: {Wait:SS1,if S0Pulse:SS+1,if S0 其中`S`为信号量计数器。

进阶话题[编辑 | 编辑源代码]

  • Monitor vs Mutex:Monitor是轻量级的,仅在同一进程内有效;Mutex支持跨进程。
  • Monitor.TryEnter:支持超时机制,避免无限等待。

模板:警告