同时将项目排队

时间:2012-08-08 15:12:02

标签: c# concurrency parallel-processing

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

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 个答案:

答案 0 :(得分:2)

假设您使用的是.NET 4.0或更高版本且确实需要队列,那么最佳解决方案是切换到使用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
}

答案 1 :(得分: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();
        }
    }

答案 2 :(得分: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();
        }
    }     
}

答案 3 :(得分: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();
  }
}