0

假设我们有两个线程使用下面执行的方法:

while(true){

    if(Queue.Count() <= 0){
        wait();
    }

    object anObject = Queue.Dequeue();
}

现在问题发生在 Queue 有一个元素 init,Thread 1 即将执行 Queue.Count 行,Thread 2 about 在 Queue.Dequeue() 上,执行优先级在 Thread 1 上。

当这种情况发生时,线程 1 将抛出异常,因为 Queue.Count() 将返回 1 并尝试从空队列中取出对象。我该如何处理?如果我想安全地出队,最好的解决方案是什么?我应该使用同步还是锁定某些东西?

最好的问候,凯末尔

4

4 回答 4

2

最好的解决方案,假设您使用的是 .NET 4.0 或更高版本并且确实需要一个 queue,是切换到使用ConcurrentQueue及其 TryDequeue 方法。ConcurrentQueue 是线程安全的。

也就是说,从您的代码片段来看,您真正在寻找的是一个线程安全的生产者/消费者队列。在这种情况下,使用BlockingCollection类和它的 Take 方法:

while(true){
    // This will block until an item becomes available to take.
    // It is also thread safe, and can be called by multiple 
    // threads simultaneously. When an item is added, only one
    // waiting thread will Take() it
    object anObject = myBlockingCollection.Take();

    // do something with anObject
}
于 2012-08-08T15:14:34.843 回答
1

您可以使用线程安全队列ConcurrentQueue

或者如果你不想使用它

    while (true)
    {
        Monitor.Enter(lockObj);
        try
        {
            if (Queue.Count <= 0)
            {
                Monitor.Wait(lockObj);
            }

            object anObject = Queue.Dequeue();
        }
        finally
        {
            Monitor.Exit(lockObj);
        }
    }

或者如果使用lock

    while (true)
    {
        lock(lockObj)
        {
            if (Queue.Count <= 0)
            {
                Monitor.Wait(lockObj);
            }

            object anObject = Queue.Dequeue();
        }
    }
于 2012-08-08T15:14:50.907 回答
0

在访问之前锁定队列。

lock (Queue) {
    // blah blah
}

编辑

while(true){
    lock (Queue) {
        if (Queue.Count() > 0) {
            // Dequeue only if there is still something in the queue
            object anObject = Queue.Dequeue();
        }
    }     
}
于 2012-08-08T15:15:18.697 回答
0

试试这个模式:

制片人

public void Produce(object o)
{
  lock (_queueLock)
  {
    _queue.Enqueue(o);
    Monitor.Pulse(_queueLock);
  }
}

消费者

public object Consume()
{
  lock (_queueLock)
  {
    while (_queue.Count==0)
    {
      Monitor.Wait(_queueLock);
    }
    return _queue.Dequeue();
  }
}
于 2012-08-08T15:21:25.640 回答