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

Posted

技术标签:

【中文标题】为啥我们需要在 C# 中锁定和对象?【英文标题】:Why do we need to lock and object in C#?为什么我们需要在 C# 中锁定和对象? 【发布时间】:2017-03-19 13:10:32 【问题描述】:

这是我一直无法理解的。创建一个获得locked 的虚拟对象几乎就像是一种黑客攻击,就像示例一样

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;  
          
      
  

会等价吗?

【问题讨论】:

@Sayse 一点也不,否则没人会明白如何首先使用locklock语句需要传入参数的原因很清楚,如果作者不理解这些原因,这个问题是非常有效的。 @rucamzu - 我想我误读了这个问题 【参考方案1】:

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

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

编辑

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

【讨论】:

是的,你是对的,我看错了,我认为他不明白 lock 在做什么。感谢您的评论 @mybirthname 完全没有问题。只是为了记录,我发现你的解释清楚而有用。【参考方案2】:

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

    只有一个线程可以进入拥有thisLock的这段代码 任何其他被thisLock锁定的部分也不允许被除了这个线程之外的任何线程进入,因为这个线程有thisLock。

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

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

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

【讨论】:

以上是关于为啥我们需要在 C# 中锁定和对象?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要在 C# 中装箱和拆箱?

为啥原子操作需要独占缓存访问?

C#中lock死锁

c#里为啥有的使用时函数需要new一个对象而有的不用?为啥不直接调用就好?

为啥我需要覆盖 C# 中的 .Equals 和 GetHashCode [重复]

为啥 MVCC 需要对 DML 语句进行锁定