0

以下で実行されるメソッドで動作する 2 つのスレッドがあるとします。

while(true){

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

    object anObject = Queue.Dequeue();
}

Queue に 1 つの要素 init があり、スレッド 1 が Queue.Count 行を実行しようとしており、スレッド 2 が Queue.Dequeue() にあり、実行優先度がスレッド 1 にある場合に問題が発生します。

この状況が発生すると、Queue.Count() が 1 を返し、空のキューからオブジェクトをデキューしようとするため、スレッド 1 は例外をスローします。どうすればこれを処理できますか? 安全にデキューしたい場合の最善の解決策は何ですか? 同期を使用するか、何かをロックする必要がありますか?

よろしく、 ケマル

4

4 に答える 4

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
}
于 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 に答える