首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >联锁Monitor.Enter和Monitor.Exit块

联锁Monitor.Enter和Monitor.Exit块
EN

Stack Overflow用户
提问于 2011-08-01 18:20:21
回答 2查看 1.3K关注 0票数 6

ECMA-335规范规定如下:

*获取锁(System.Threading.Monitor.Enter或输入同步方法)应隐式执行易失性读取操作,释放锁(System.Threading.Monitor.Exit或离开同步方法)将隐式执行易失性写入操作。(...)

易失性读取具有获取语义,意味着在CIL指令序列中的读指令之后发生的对存储器的任何引用之前,读取被保证发生。易失性写入具有发布语义,这意味着在CIL指令序列中的写入指令之前的任何内存引用之后,写入都将发生。

这意味着编译器不能将语句从Monitor.Enter/Monitor.Exit块中移出,但不禁止将其他语句移动到块中。也许,甚至可以将另一个Monitor.Enter移到块中(因为易失性写入和易失性读取可以交换)。因此,可以使用以下代码:

代码语言:javascript
复制
class SomeClass
{
    object _locker1 = new object();
    object _locker2 = new object();

    public void A()
    {
        Monitor.Enter(_locker1);
        //Do something
        Monitor.Exit(_locker1);
        Monitor.Enter(_locker2);
        //Do something
        Monitor.Exit(_locker2);
    }

    public void B()
    {
        Monitor.Enter(_locker2);
        //Do something
        Monitor.Exit(_locker2);
        Monitor.Enter(_locker1);
        //Do something
        Monitor.Exit(_locker1);
    }
}

,变成相当于以下内容的东西:

代码语言:javascript
复制
class SomeClass
{
    object _locker1 = new object();
    object _locker2 = new object();

    public void A()
    {
        Monitor.Enter(_locker1);
        //Do something
        Monitor.Enter(_locker2);
        Monitor.Exit(_locker1);
        //Do something
        Monitor.Exit(_locker2);
    }

    public void B()
    {
        Monitor.Enter(_locker2);
        //Do something
        Monitor.Enter(_locker1);
        Monitor.Exit(_locker2);
        //Do something
        Monitor.Exit(_locker1);
    }
}

可能会导致死锁?还是我漏掉了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-08-01 18:49:09

ECMA-335规范比CLR (和所有其他实现)使用什么?弱得多.

我记得我读过(异端邪说)微软第一次尝试使用较弱的内存模型移植到IA-64。他们有太多自己的代码依赖于双重检查的锁定成语(在较弱的内存模型下是断了 ),所以他们只是在这个平台上实现了更强的模型。

Joe已经为我们这些普通人总结了(实际的) CLR内存模型。还有一个链接到MSDN文章,更详细地解释了CLR与ECMA-335的不同之处。

我不认为这在实践中是一个问题;只要假设CLR内存模型,因为其他人都这样做。此时没有人会创建一个弱实现,因为大多数代码都会崩溃。

票数 2
EN

Stack Overflow用户

发布于 2011-08-01 18:37:07

当您使用lockMonitor.EnterMonitor.Exit时,这是满栅栏,这意味着它将在开始时或锁"Monitor.Enter“和锁"Monitor.Exit”结束之前在内存Thread.MemoryBarrier()中创建一个“屏障”。因此,没有操作将在锁之前和之后移动,但是请注意,锁本身内的操作可以从其他线程透视图中交换,但这从来不是一个问题,因为锁将保证互斥,因此只有一个线程将同时在锁内执行代码。无论如何,重新排序不会在单个线程中发生,也就是说,当多线程输入相同的代码区域时,它们可能会看到不同顺序的指令。

我强烈建议您在文章中阅读更多关于和完整和半栅栏的内容。

编辑:注意到,这里我描述的事实是,lock是完全隔离的,但没有提到您所知道的“死锁”,您所描述的场景永远不会发生,因为就像@提到的那样,方法调用的重新排序永远不会发生,即:

代码语言:javascript
复制
Method1();
Method2();
Method3();

将始终按顺序执行,但其中的指令可能会重新排序,就像多线程执行Method1()中的代码时一样。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6902612

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档