C#“lock”关键字:为什么语法需要一个对象?

时间:2014-07-31 20:27:48

标签: c# thread-safety

要将代码标记为关键部分,我们会这样做:

Object lockThis = new Object();    
lock (lockThis)
{    
     //Critical Section
}

为什么有必要将对象作为锁定语法的一部分?换句话说,为什么不能这样做:

lock
{
   //Critical Section
}

3 个答案:

答案 0 :(得分:2)

需要使用某些东西作为锁。

这样两种不同的方法可以共享同一个锁,因此一次只能使用一个。

Object lockThis = new Object();    

void read()
{
  lock (lockThis)
  {    
     //Critical Section
  }
}
void write()
{
  lock (lockThis)
  {    
     //Critical Section
  }
}

答案 1 :(得分:2)

因为您不会锁定 - 您锁定某些内容(锁定锁定)。

锁定点是禁止两个线程直接竞争同一资源。因此,您将该资源隐藏在任意对象后面。任意对象充当锁。当一个线程进入临界区时,它会锁定锁,而其他线程无法进入。当线程在关键部分完成其工作时,它会解锁并将键留出,以便接下来发生的任何线程。 / p>

如果一个程序有一个资源是竞争访问的候选者,那么它可能还有其他这样的资源!但是这些资源通常是彼此独立的 - 换句话说,一个线程能够锁定一个特定资源和另一个线程同时能够锁定另一个资源而没有那两个干扰可能是有意义的。

也可能需要从两个关键部分访问资源。这两个人需要拥有相同的锁。如果每个人都有自己的,那么他们就无法有效保持资源无可争议。

显然,我们不会锁定 - 我们锁定每个特定资源的锁定。但编译器无法自动生成该任意锁定对象,因为它不知道哪些资源应该使用相同的锁来锁定,哪些资源应该拥有自己的锁。这就是为什么你必须明确说明哪个锁保护哪个块(或阻止)代码的原因。

请注意,正确使用对象作为锁要求对象是持久的(至少与对应的资源一样持久)。换句话说,您无法在本地范围内创建它,将其存储在局部变量中并在范围退出时将其丢弃,因为这意味着您实际上并未实际锁定任何内容。如果有一个持久对象充当给定资源的锁,则只有一个线程可以进入该节。如果每次有人试图进入时都会创建一个新的锁定对象,那么任何人都可以随时进入。

答案 2 :(得分:1)

嗯,简单的答案就是语言的指定方式。锁需要有某种对象来锁定。这允许您通过控制此对象的范围和生命周期来控制必须锁定的代码。请参阅lock Statement (C# Reference)

该语言的设计者可能已经提供了像您所建议的匿名式锁,并依赖编译器在幕后生成适当的对象。但是,创建的对象应该是静态成员还是实例成员?如果您在一个类中有多个需要锁定的方法,它将如何使用?这些都是一些棘手的问题,而且我确信这种语言的设计者根本没有感觉到包含这样一个结构的好处值得增加它所带来的复杂性或混乱。