锁内锁的理由是什么?

时间:2011-12-21 07:02:35

标签: c# multithreading locking

我正在查看书中的示例代码,并遇到了以下代码(简化)。 在代码中,当调用Subscribe(T subscriber)时,线程进入锁定部分。 然后,当锁内部的代码调用AddToSubscribers(T subscriber)方法时,该方法有另一个锁。为什么这第二次锁是必要的?

public abstract class SubscriptionManager<T> where T : class 
{
   private static List<T> subscribers;
   private static void AddToSubscribers(T subscriber)
   {
      lock (typeof(SubscriptionManager<T>))
      {
         if (subscribers.Contains(subscriber))
            return;
         subscribers.Add(subscriber);
      }
   }

   public void Subscribe(T subscriber)
   {
      lock (typeof(SubscriptionManager<T>))
      {
         AddToSubscribers(subscriber);
      }
   }
}

4 个答案:

答案 0 :(得分:10)

在这种情况下,它不是;但是,因为锁是可重入的,可以用来确保AddToSubscribers的任何其他调用者都能观察到锁。实际上,出于这个原因,我会说“将其从Subscribe中删除,然后让AddToSubscribers执行锁定”。

然而!锁定Type非常危险。一个字段会更安全:

// assuming static is correct
private static readonly object syncLock = new object();

lock(syncLock)。根据分配subscribers的时间,您可能还会使用lock(subscribers)(并且没有额外的字段)。

我还应该注意,将实例方法添加到静态状态非常......非同寻常; IMO Subscribe应该是static方法,因为它与当前实例无关。

答案 1 :(得分:4)

在您发布的代码中,没有必要。但话说回来,您发布的代码不完整 - 例如订阅者列表从未初始化。

锁定typeof(SubscriptionManager)可能也不是一个好主意 - 锁定subscribers字段会更好 - 但需要初始化subscriber字段,例如

private static List<T> subscribers = new List<T>();

答案 2 :(得分:2)

您可能应该阅读该示例附近的内容并查看该书的内容。

对于那个特例 - 不,不需要第二次锁定。

注意:样本很危险,因为它锁定了公共对象(类型)。通常一个锁定特殊私有对象,因此外部代码无法通过错误地锁定同一对象而错误地引入死锁。

答案 3 :(得分:1)

我曾经遇到过一种情况,我不得不使用嵌套的锁。

我的情况是,第二个锁的功能可能是从其他地方调用的,因为它是一个静态函数。但是,对于您的情况,由于每个数据成员都属于一个实例而不是静态的,因此没有必要。