3

我正试图围绕lock 语句中究竟发生了什么。

如果我理解正确,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

4 回答 4

3

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

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

对这样一个变量的硬性要求是它是在任何 lock 语句使用它之前创建的。尝试按照您的建议即时创建它会产生一个新问题,现在需要使用锁来安全地创建变量,以便只有进入锁的第一个线程创建它,而其他线程试图进入锁在创建之前被阻塞。这需要一个变量。等等,一个无法解决的先有鸡还是先有蛋的问题。

于 2012-12-29T21:07:46.253 回答
2

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

于 2012-12-29T21:15:19.243 回答
1

In order for the no-variable thing to work, you'd have to either:

  • Have one auto-generated lock variable per lock block (what you did, which means that you can't have two different lock blocks locking on the same variable)
  • Use the same lock variable for all lock blocks in the same class (which means you can't have two independent things protected)

Plus, you'd also have the issue of deciding whether those should be instance-level or static.

In the end, I'm guessing the language designers didn't feel that the simplification in one specific case was worth the ambiguity introduced while reading code. Threading code (which is the reason to use locks) is already hard to write correctly and verify. Making it harder would be a not-good thing.

于 2013-01-01T02:27:27.427 回答
0

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

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

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

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

编辑:

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

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

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

于 2012-12-29T21:17:01.217 回答