2011-10-20 8 views
1

以下のコードは、2つのパラメータを指定して送信されるソケットメッセージを処理します。情報をキューに入れ、別のスレッドで処理されます。私の質問は、2つのメッセージが直後に来て、デキューされてProcessDataメソッドに送られた場合です。ProcessDataに競合状態がありますか?キューのレース条件

private void DataIn(long Code, string Message) 
{ 
    if (!Started) 
    { 
    if (DataInQueue == null) 
     DataInQueue = new Queue(); 
    DataInThread = new Thread(new ThreadStart(ThreadProcedure)); 
    DataInThreadEnding = false; 
    DataInThread.IsBackground = true; 
    DataInThread.Start(); 
    Started = true; 
    } 
    DataInQueue.Enqueue(new cDataIn(Code, Message)); 
} 

private void ThreadProcedure() 
{ 
    while (!ProgramEnding) 
    { 
    Queue mySyncdQ = Queue.Synchronized(DataInQueue); 
    if (mySyncdQ != null && mySyncdQ.Count > 0) 
    { 
     cDataIn data = null; 
     // Creates a synchronized wrapper around the Queue. 
     if (mySyncdQ.Count > 0) 
      data = (cDataIn)mySyncdQ.Dequeue(); 

     ProcessData(data); 
    } 
    } 

} 

答えて

5

UPDATE

キューがあなたのコード内でスレッドセーフな方法で使用されていません...あなたが表示されたコードは、競合状態が存在するかどうかを確認するには十分ではなく、ConcurrentQueueであなたが得ますより良いパフォーマンス...そしてThreadProcedureではnullでProcessDataを呼び出すことができますし、安全な側にあることがわかるようにProcessDataはすべての機能が再入可能でなければなりません。

ConcurrentQueue - いくつかの可能な問題を避けています...そして、スレッドセーフなプロデューサ/スレッド用に設計されたBlockingCollectionをチェックしてください。コンシューマーシナリオ...どちらもほとんどロックフリーですが、実際には高速です...

+0

問題があると言っていますか? – Jon

+1

Queueクラスのドキュメント(http://msdn.microsoft.com/en-us/library/system.collections.queue(v=VS.100).aspx)には、スレッドの安全性に関する段落があります。インスタンスメンバーはTSではありません。私は実装を見て、coudが何かを見ていないが、あなたは2つのスレッドをスピンアップすることで自分自身を確認することができます。 1つは順次メッセージ(1,2,3、..)でポンプし、もう一方はそれらを読み込みます。あなたはたぶん例外やギャップ/ダブルス(1,2,2,4,5、...)を得るでしょう。 – gjvdkamp

+0

上記の私の更新を参照してください... – Yahia

4

はいこれはあなたのキューを矛盾した状態にすることさえできます。 .Net 4.に同梱されているConcurrent QueueBlockingCollectionを使用する必要があります。これは、箱から取り出して最適化したスレッドセーフです。

よろしくゲルト・ヤン

+0

http://blog.mischel.com/2011/03/22/memory-leak-in-concurrentqueue/ – Jon

+0

なぜキューに問題がありますか? ProcessDataが素早く呼び出され、2番目のスレッドが最初に – Jon

+0

@Jonを追い越す可能性があることを心配していましたが、メモリリークはほとんど影響を受けません。 – svick

3

あなたのコードはスレッドセーフではありません。 the documentation for Queue.Synchronized()でこれを注意してください:

Queueのスレッドの安全性を保証するために、すべての操作はこれだけラッパーを介して行う必要があります。

コードはスレッドセーフではないため、キューを直接使用しています。これを修正するには、ドキュメントにあるように、常に返されるラッパーを使用してください。

または、.Net 4の場合は、ConcurrentQueue<T>を使用してください。

以前のバージョンの.Netで汎用キューを使用する場合は、Queue<T>を使用し、常にlockにアクセスします。

+0

私は私がエンキューとデキュー時に同期を呼び出す必要がありますか? – Jon

+0

それは、ドキュメンテーションが言っていることですね。 – svick

+0

エンキューとデキューについては実際には言いません。 – Jon

関連する問題