Lock和Monitor的区别

本文对比分析了Lock与Monitor两种同步机制的特点与使用方法。Lock为Monitor的简化版,仅支持引用类型的锁定;而Monitor支持值类型锁定,但在锁定期间不可修改锁定对象。此外,Monitor还提供了更多高级功能,如TryEnter、Wait、Pulse和PulseAll等。

 

Lock Monitor的简化版本,IL

callvirt ...Monitor.Enter(object)
...
leave.s
....
callvirt ...Monitor.Exit(object)

Lock 只能对引用对象加锁

Lock锁定区间内可以对锁定值修改而不发生运行时错误,通常也会采用此种修改方式。这种方式又有点类同于使用Monitor.Wait 取得资源,并对这个资源进行操作。

lock (lockObj)

{

    lockObj = newObj;

}

 

Monitor 可以对值类型加锁,实际上是在调用Monitor.Enter时对值类型装箱了

Monitor在锁定区域内不能对被锁对象的值进行修改,运行时抱错“从不同步的代码块中调用了对象同步方法

int lockInt = 0;

try

{

    Monitor.Enter(lockInt);

    lockInt = newValue;

}

catch

{

 

}

finally

{

    Monitor.Exit(newValue);

}

Monitor 相对Lock有其他一些复杂功能

Monitor.TryEnter

//Try to add an element to the queue.

//Add the element to the queue only if the queue object is unlocked.

public bool AddElementWithoutWait(object qValue)

{

    //Determine whether the queue is locked

    if (!Monitor.TryEnter(m_inputQueue))

        return false;

    m_inputQueue.Enqueue(qValue);

 

    Monitor.Exit(m_inputQueue);

    return true;

}

 

//Try to add an element to the queue.

//Add the element to the queue only if during the specified time the queue object will be unlocked.

public bool WaitToAddElement(object qValue, int waitTime)

{

    //Wait while the queue is locked.

    if (!Monitor.TryEnter(m_inputQueue, waitTime))

        return false;

    m_inputQueue.Enqueue(qValue);

    Monitor.Exit(m_inputQueue);

 

    return true;

}

Monitor.Wait

Monitor.Pulse

Monitor.PulseAll

Monitor.Wait(m_smplQueue);

//Push one element.

m_smplQueue.Enqueue(counter);

//Release the waiting thread.

Monitor.Pulse(m_smplQueue);

Monitor.PulseAll(m_smplQueue);

Wait: 等待得到被锁对象,可以对被锁对象进行操作

Pulse: 释放当前锁定操作对象,下一个等待该对象的Wait将得到对象的使用权
PulseAll
:释放当前锁定对象,所有正在等待该对象得Wait将同时得到释放(进入下一行代码,可以认为不在对该对象进行同步控制)

Tag标签: 多线程, 同步, Lock, Monitor
0
0
(请您对文章做出评价)
以下是关于 `lock` `Monitor` 在 C# 多线程编程中的深度对比解析: --- ### **1. 核心机制对比** | 特性 | `lock` 关键字 | `Monitor` 类 | |---------------------|----------------------------------|---------------------------------------| | **实现层级** | 语法糖(编译后转为Monitor调用) | 基础同步原语 | | **代码简洁性** | ✅ 自动生成 try/finally 块 | ❌ 需手动编写 Enter/Exit | | **超时控制** | ❌ 不支持 | ✅ 支持 TryEnter(timeout) | | **中断处理** | ❌ 无响应中断 | ✅ Pulse/Wait 实现线程通信 | | **性能开销** | 较低(JIT优化) | 稍高(需显式调用) | --- ### **2. 底层实现原理** #### **(1) `lock` 的编译结果** ```csharp // 原始代码 lock(obj) { /* 临界区 */ } // 等效IL代码 Monitor.Enter(obj); try { /* 临界区 */ } finally { Monitor.Exit(obj); } ``` **关键优化**:JIT 编译器会对无竞争的锁进行快速路径优化 #### **(2) Monitor 的同步机制** ```mermaid sequenceDiagram participant T1 as 线程A participant S as SyncBlock participant T2 as 线程B T1->>S: Monitor.Enter(obj) S->>S: 记录Owner=ThreadA T2->>S: Monitor.Enter(obj) (竞争) S->>T2: 进入等待队列 T1->>S: Monitor.Exit(obj) S->>T2: 唤醒并获取锁 ``` --- ### **3. 高级用法对比** #### **(1) 超时控制示例** ```csharp // Monitor 实现带超时的锁 if (Monitor.TryEnter(obj, 500)) { try { // 临界区 } finally { Monitor.Exit(obj); } } else { // 处理超时逻辑 } ``` #### **(2) 线程通信(生产者-消费者)** ```csharp // 使用 Monitor 的 Pulse/Wait private object _sync = new object(); private Queue<object> _queue = new Queue<object>(); // 生产者 lock (_sync) { _queue.Enqueue(data); Monitor.Pulse(_sync); // 唤醒等待线程 } // 消费者 lock (_sync) { while (_queue.Count == 0) { Monitor.Wait(_sync); // 释放锁并等待 } return _queue.Dequeue(); } ``` --- ### **4. 性能关键指标** | 操作 | 平均耗时 (ns) | |---------------------|--------------| | `lock` (无竞争) | 20-40 | | `Monitor.Enter` | 25-50 | | 竞争锁(上下文切换)| 1000+ | | `Pulse` 信号 | 150-200 | **最佳实践**: - 高频锁考虑使用 `SpinLock`(当竞争时间 < 1μs) - 长时间操作优先用 `Monitor` + 超时 - 避免锁嵌套(易引发死锁) --- ### **5. 异常处理模式** #### **(1) `lock` 的隐式保护** ```csharp lock (obj) { throw new Exception(); // 仍能保证锁释放 } // 等效于: Monitor.Enter(obj); try { throw new Exception(); } finally { Monitor.Exit(obj); // 异常时仍执行 } ``` #### **(2) Monitor 的显式控制风险** ```csharp Monitor.Enter(obj); // 如果此处抛出异常... DoSomething(); // ...会导致锁泄漏 Monitor.Exit(obj); // 不会被执行 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值