为什么在锁定语句中指定同步对象是必需的

时间:2012-12-29 21:05:36

标签: c# synchronization locking

我试图围绕lock statement中的确切情况进行思考。

如果我理解正确,那么lock语句就是语法糖和以下......

Object _lock = new Object();

lock (_lock)
{
    // Critical code section
}

......被翻译成大致类似的东西:

Object _lock = new Object();

Monitor.Enter(_lock);
try
{
    // Critical code section
}
finally { Monitor.Exit (_lock); }

我已经多次使用了lock语句,并且总是创建一个私有字段_lock,作为专用的同步对象。我明白为什么你不应该锁定公共变量或类型。

但为什么编译器也不会创建该实例字段?我觉得事实上可能存在开发人员想要指定锁定内容的情况,但根据我的经验,在大多数情况下,这绝对没有兴趣,你只需要锁定!那么为什么没有无参数的锁超载?

lock()
{
   // First critical code section
}

lock()
{
   // Second critical code section
}

将被翻译成(或类似):

[DebuggerHidden]
private readonly object _lock1 = new object()

[DebuggerHidden]
private readonly object _lock2 = new object()

Monitor.Enter(_lock1);
try
{
    // First critical code section
}
finally { Monitor.Exit(_lock1); }

Monitor.Enter(_lock2);
try
{
    // Second critical code section
}
finally { Monitor.Exit(_lock2); }

编辑:我显然不清楚多个锁定语句。更新了问题以包含两个锁定语句。

4 个答案:

答案 0 :(得分:3)

需要存储锁的状态。是否输入。这样可以阻止另一个尝试进入同一个锁的线程。

这需要一个变量。只是一个非常简单的对象就足够了。

对此类变量的一个硬性要求是在任何锁定语句使用它之前创建。试图在你提出的时候即时创建它会产生一个新问题,现在需要使用一个锁来安全地创建变量,这样只有进入锁的第一个线程才能创建它,而其他线程试图进入锁被锁定,直到它被创建。这需要一个变量。 Etcetera,一个无法解决的鸡蛋问题。

答案 1 :(得分:2)

在某些情况下,您需要两个不同的lock,它们彼此独立。意思是当一个“可锁定”的代码部分被锁定时,其他“可锁定”不应该被锁定。这就是为什么能够提供锁定对象的原因 - 你可以为几个独立的lock提供几个

答案 2 :(得分:1)

为了使无变量的东西起作用,你必须要么:

  • 每个锁定块有一个自动生成的锁定变量(你做了什么,这意味着你不能在同一个变量上锁定两个不同的锁定块)
  • 对同一个类中的所有锁定块使用相同的锁定变量(这意味着您不能保护两个独立的东西)

另外,您还有一个问题,即决定这些应该是实例级还是静态。

最后,我猜测语言设计者并不认为在一个特定情况下的简化值得在阅读代码时引入歧义。线程代码(这是使用锁的原因)已经很难正确编写并验证。让它变得更难是一件好事。

答案 3 :(得分:0)

允许隐式锁定对象可能会鼓励使用单个锁定对象,这被认为是不好的做法。通过强制使用显式锁对象,该语言鼓励您将锁命名为有用的东西,例如“countIncementLock”。

如此命名的变量不会鼓励开发人员在执行完全独立的操作时使用相同的锁对象,例如写入某种流。

因此,对象可能是在一个线程上写入一个流,而在另一个线程上增加一个计数器,并且这两个线程都不一定会相互干扰。

语言不会这样做的唯一原因是因为它看起来像是一种好习惯,但实际上却隐藏了一种不好的做法。

修改

也许C#的设计者不想要隐式锁变量,因为他们认为它可能会鼓励不良行为。

也许设计师根本没有想到隐式锁定变量,因为他们首先要考虑其他更重要的事情。

如果每个C#开发人员确切地知道他们写lock()时发生了什么,并且他们知道其含义,那么就没有理由为什么它不应该存在,并且没有理由为什么它不应该如何工作?建议。