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

时间:2016-11-05 22:46:07

标签: c# .net multithreading asynchronous

这是我从未理解过的。创建一个获得lock ed的虚拟对象,就像示例

一样
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;  
        }  
    }  
}  

会等同吗?

2 个答案:

答案 0 :(得分:7)

传递给lock的实例用于识别关键部分

您的代码中可能包含任意数量的不相关的关键部分,每个部分都将锁定不同的对象。无参数lock语句与您建议的语句类似,无法区分许多关键部分。

修改

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

答案 1 :(得分:1)

我认为混淆在于lock关键字正在做什么。这并不是说只有一个线程可以进入该部分代码,但它说的是两件事:

  1. 只有一个线程可以进入具有thisLock
  2. 的代码段
  3. 除了此线程之外,任何其他被thisLock锁定的部分也不允许进入该线程,因为该线程具有此锁定。
  4. 你所建议的只是做第一个而不是两个。看看这个例子:

    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)正在使用第一个锁执行提取部分时,具有锁(thisLock)的类的所有其他部分也不允许任何其他线程进入。但是,允许使用thisLock2的部分由其他线程输入。

    考虑锁定关键字的最佳方式,至少在我学习时帮助我的是将其视为人质。换句话说,当代码的某些部分正在执行时,它需要在您的示例中使用人质(thisLock)。因此,一旦将thisLock视为人质,在该线程释放人质之前,没有其他线程可以将其作为人质。因此,所有其他需要相同人质的代码部分也将无法使用。