我可以使用字典元素作为锁定对象吗?

时间:2013-06-07 12:49:56

标签: c# multithreading locking

我有多个队列正在被多个线程访问。为了实现线程安全,我做了以下几点:

private static Dictionary<string, Queue<string>> MyQueues = new Dictionary<string, Queue<string>>();

public static string GetNextQueueElementForKey(string key)
{
    string res = string.Empty;

    if (MyQueues.Keys.Contains(key))
    { 
       Queue<string> queue = MyQueues[key];
       lock (queue)
       {
           if (queue.Count() > 0)
           {
               res = queue.Dequeue();
           }
       }
   }

   return res;
}

我也可以锁定MyQueues,但是我会锁定超过必要的数量。所以我的问题是,如果锁定字典中包含的对象将起作用 - 假设一个键的值(队列)永远不会改变。

3 个答案:

答案 0 :(得分:7)

可以 - 但我通常不会。就个人而言,我通常会尝试锁定那些不用于其他任何事情的普通System.Object实例,理想情况下甚至不会暴露于除锁定类之外的任何代码。这样你就可以绝对确定没有别的东西可以锁定。

在这种情况下,看起来你已经控制了队列,所以你知道它们不会被其他代码使用,但可能 Queue<T>内的代码将会锁定this。这可能不是这样,但这是我会担心的事情。

从根本上说,我希望.NET没有采用Java的“每个对象的监视器”的方法 - 我希望Monitor是一个可实例化的类。

(我假设你实际上只是从多个线程的字典中读取 ?使用字典进行多线程读/写是不安全的。)

答案 1 :(得分:2)

它是字典中的元素这一事实在很大程度上是无关紧要的 - 只要它是一个引用类型(Queue<string> ) - 然后每个队列,当从字典,每次都是相同的object实例。这意味着它可以完全合理地锁定每个队列级别。

所以基本上:是的,只要Enqueue执行相同的每队列锁定,这应该可以正常工作。正如乔恩所说 - 无论你应该这样做是另一个问题。

就个人而言,我仍然认为Monitor应该是非静态类型,并且您只能锁定Monitor个实例,而不是object。< / p>

答案 2 :(得分:1)

  

所以我的问题是,如果锁定字典中包含的对象将起作用 - 假设一个键的值(队列)永远不会改变。

在这里查看您的代码:

lock (queue) {
    if (queue.Count() > 0) {
        res = queue.Dequeue();
    }
}

可以,但我这样做。您应该never lock on the object itself,因为您可能会与其他代码线程竞争,这些代码将锁定同一个对象,包括Queue<T>本身(谁可以锁定this )。

因此,至少应该为每个队列创建一个专用的锁定对象。

但是,您有没有使用ConcurrentQueue<T>的原因?这是最简单的解决方案,并将负责任的问题转移到框架上。