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

Sea*_*ean 6 c# thread-safety

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

Object lockThis = new Object();    
lock (lockThis)
{    
     //Critical Section
}
Run Code Online (Sandbox Code Playgroud)

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

lock
{
   //Critical Section
}
Run Code Online (Sandbox Code Playgroud)

The*_*kis 4

因为你不只是锁——你锁了一些东西(你锁了一把锁)。

锁定的目的是不允许两个线程直接竞争同一资源。因此,您将该资源隐藏在任意对象后面。该任意对象充当锁。当一个线程进入临界区时,它会锁定该锁,其他线程无法进入。当线程完成临界区中的工作时,它会解锁并将密钥留给下一个恰好出现的线程。

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

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

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

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