You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么C#编译器处理lock语句时会拷贝一份临时锁变量?

C# lock语句生成临时锁对象变量的原因

编译器新增临时变量存储锁对象,核心是为了保证Monitor.Enter和Monitor.Exit操作的始终是同一个对象实例,避免出现锁泄漏、错误释放其他对象等严重问题,具体原因如下:

  • 避免锁变量被修改导致锁逻辑异常
    如果直接使用原变量mylock,一旦在Monitor.Enter执行完成后到finally执行前的这段时间里,mylock的指向被修改(不管是锁块内部代码修改,还是其他并发线程修改),finally块里的Monitor.Exit操作就会作用在修改后的新对象上:
    • 你实际持有的旧锁对象永远不会被释放,造成锁泄漏,后续所有尝试获取该旧对象锁的代码都会永久阻塞
    • 如果新对象已经被其他线程持有锁,你尝试释放不属于自己的锁还会抛出异常

举个会触发问题的代码示例:

public object mylock = new object();
void BadCaseTest()
{
    bool lockTaken = false;
    try
    {
        Monitor.Enter(mylock, ref lockTaken);
        // 此处修改了原锁变量的指向
        mylock = new object();
    }
    finally
    {
        if (lockTaken)
        {
            // 这里释放的是新创建的对象,不是实际持有的旧锁对象
            Monitor.Exit(mylock);
        }
    }
}

用临时变量存储进入lock语句时的锁对象后,不管后续原变量mylock怎么修改,Enter和Exit都是作用在同一个对象上,完全规避了上述问题。

  • 严格符合C#语言规范的语义定义
    C#语言规范明确规定:lock语句的锁定对象是进入lock块时,对锁定表达式求值得到的结果实例,后续该表达式对应的变量发生任何变更都不影响本次lock的锁定对象。临时变量的实现就是对该语义的严格落地。

内容的提问来源于stack exchange,提问作者leadingwerido

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 23:45:09