6

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

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

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

4

3 回答 3

7

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

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

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

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

于 2013-06-07T12:54:48.033 回答
2

它是字典中的一个元素这一事实在很大程度上是无关紧要的——只要它是一个引用类型(即Queue<string> ——那么每个队列,当从字典中获取时,object每次都将是同一个实例。这意味着它将在每个队列级别锁定完美合理地工作。

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

就个人而言,我仍然认为Monitor应该是非静态类型,并且您只能锁定Monitor实例,而不是任何object.

于 2013-06-07T12:55:11.733 回答
1

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

在这里查看您的代码:

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

可以,但我会这样做。您永远不应该锁定对象本身,因为您可能会与将锁定同一对象的其他Queue<T>代码线程竞争,包括它自己(谁可以锁定this)。

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

但是,有没有你不使用的原因ConcurrentQueue<T>?那将是最简单的解决方案,并将正确处理它的负担转移到框架中。

于 2013-06-07T12:55:52.020 回答