为什么我们需要在 C# 中锁定和对象?

Why do we need to lock and object in C#?

这是我一直不明白的事情。创建一个得到 locked 的虚拟对象几乎像是一种 hack,就像示例

class Account  
{  
    decimal balance;  
    private Object thisLock = new Object();  

    public void Withdraw(decimal amount)  
    {  
        lock (thisLock)  
        {  
            if (amount > balance)  
            {  
                throw new Exception("Insufficient funds");  
            }  
            balance -= amount;  
        }  
    }  
}  

来自 https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

为什么语言设计者不能做到

class Account  
{  
    decimal balance;   

    public void Withdraw(decimal amount)  
    {  
        lock 
        {  
            if (amount > balance)  
            {  
                throw new Exception("Insufficient funds");  
            }  
            balance -= amount;  
        }  
    }  
}  

是否等价?

传递给 lock 的实例用于识别临界区

您的代码中可能有任意数量的不相关关键部分,每个关键部分将锁定不同的对象。一个无参数的 lock 语句,就像你建议的那样,将无法区分许多关键部分。

编辑

虽然这看起来很明显,但值得注意的是,需要进入给定临界区的每个部分都必须能够访问锁定的对象。所以这不是在 lock 语句之前和在相同范围内创建任意实例的问题。

我认为混淆在于 lock 关键字的作用。这并不是说只有 1 个线程可以进入那段代码,而是说两件事:

  1. 只有拥有thisLock的线程才能进入这段代码
  2. 除此线程之外的任何线程也不允许使用此锁锁定的任何其他部分,因为此线程具有此锁。

你的建议是只做第一个而不是两个。看这个例子:

class Account
{
    decimal balance;
    private Object thisLock = new Object();
    private Object thisLock2 = new Object();

    public void Withdraw(decimal amount)
    {
        lock (thisLock)
        {
            if (amount > balance)
            {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }

        // more code here but no locking necessary...

        lock(thisLock)
        {
            // only one thread can enter here who has thisLock
        }

        lock (thisLock2)
        {
            // If T1 (thread1) is working with thisLock, T2 can come here since it has nothing to do
            // with thisLock.
        }
    }

    public void AnotherOperation()
    {
        lock (thisLock)
        {
            // code here...
        }
    }

    public void YetAnotherOperation()
    {
        lock (thisLock)
        {
            // code here...
        }
    }
}

当一个线程,比如 T1,正在使用第一个锁执行取款部分时,class 的所有其他带有锁(thisLock)的部分也不允许任何其他线程进入。但是有thisLock2的部分是允许其他线程进入的。

想到lock关键字的最好方法,至少在我学习的时候它帮助了我,就是把它想成一个人质。换句话说,当代码的某些部分正在执行时,它需要在您的示例中劫持人质(thisLock)。因此,一旦 thisLock 被作为人质,在该线程释放人质之前,没有其他线程可以将其作为人质。因此,所有其他也需要相同人质的代码部分将变得不可用。