Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么必须在lock语句中指定同步对象_C#_Synchronization_Locking - Fatal编程技术网

C# 为什么必须在lock语句中指定同步对象

C# 为什么必须在lock语句中指定同步对象,c#,synchronization,locking,C#,Synchronization,Locking,我正试着把我的思绪集中在未来到底发生了什么 如果我理解正确,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语句是语法糖,下面

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语句,并且总是创建一个私有字段
\u lock
,作为专用的同步对象。我确实理解为什么不应该锁定公共变量或类型

但是为什么编译器不同时创建该实例字段呢?我觉得实际上可能有开发人员想要指定锁定什么的情况,但根据我的经验,在大多数情况下,这是绝对没有兴趣的,你只想要那个锁定!那么为什么锁没有无参数过载呢

lock()
{
   // First critical code section
}

lock()
{
   // Second critical code section
}
将被翻译成(或类似):

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

需要存储锁的状态。无论是否输入。这样,另一个试图进入相同锁的线程就可以被阻止

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


这种变量的一个硬要求是在任何lock语句使用它之前创建它。正如您所建议的那样,尝试动态创建它会产生一个新问题,现在需要使用锁来安全地创建变量,以便只有进入锁的第一个线程才会创建它,而尝试进入锁的其他线程会被阻止,直到创建它为止。这需要一个变量。等等,一个无法解决的鸡和蛋的问题。

在某些情况下,您可能需要两个相互独立的
锁。这意味着当代码的一个“可锁定”部分被锁定时,其他“可锁定”部分不应被锁定。这就是为什么能够提供锁对象的原因-您可以为多个独立的
提供多个锁对象,允许隐式锁对象可能会鼓励使用单个锁对象,这被认为是不好的做法。通过强制使用显式锁对象,该语言鼓励您将锁命名为有用的名称,例如“CountIncentLock”

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

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

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

编辑:

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

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


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

为了让无变量的东西工作,您必须:

  • 每个锁块有一个自动生成的锁变量(您所做的,这意味着您不能让两个不同的锁块锁定在同一个变量上)
  • 对同一类中的所有锁块使用相同的锁变量(这意味着不能保护两个独立的对象)
另外,您还需要决定这些是实例级还是静态


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

你的建议似乎等同于锁(这个),这不是一个好主意。@empi:不,它不等同于锁(这个)
,因为锁是一个member@mousio:它在功能上是等效的,因为将有一个锁对象(\u lock)上课instance@empi:你刚才解释了为什么它不相等;那么需要锁的静态方法呢?@adabyron您已经有了一个可以应用于此方法的属性
[MethodImpl(methodimpoptions.Synchronized)]
谢谢您的回答。但是,是什么阻止了为编译器生成的变量存储状态?我不确定这是否回答了这个问题。事实上,可以使用不同的对象来实现更细粒度的锁定。编译器无法理智地推断哪个对象应该持有锁。怎么会有鸡和蛋的问题?如果字段是在字段初始值设定项中初始化的,那么它是由调用构造函数的线程创建的。当然,只能有一个线程调用给定对象的构造函数。现在,您正在对锁定变量的范围进行危险的假设。当然,假设它总是一个非静态变量是不合适的。这并不能保护具有静态作用域的共享资源,很多情况下是这样的。每个lock语句当然会创建一个单独的编译器生成的变量(例如,必须生成名称,匿名类型获取名称的方式)。但我理解你的观点:有时你想锁定同一个变量,这就是为什么无参数版本必须是重载的原因之一。@adabyron那么你如何锁定两个同步方法呢?你似乎只看一个锁方法的退化案例?一个变量。通常有多个方法使用同一个lock语句
[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); }