3つのスレッド間でデータを共有するために使用されるConcurrentQueueがあります。スレッドAは継続的にキューをデータで満たします。スレッドBは、このデータをファイルに記録するように設計されています。スレッドCは、キュー内の最も若いエントリ(または可能な限り最も若いエントリに近い)を取得し、そのエントリに対していくつかの操作を実行して、結果を画面に表示することになっています。
スレッドBは、ファイルの書き込み操作を時間内にクラスター化するために、次のようなことを行います。
if (cq.Count > 100)
{
while (cq.Count > 1)
{
qElement = PopFromCq(cq); // PopFromCq uses cq.TryDequeue()
bw.Write(qElement.data); // bw is a binary writer
}
}
else
{
System.Threading.Thread.Sleep(10);
}
つまり、少なくとも100個の要素がキューに入れられるのを待ってから、それらをディスクに書き込みます。ただし、常に少なくとも1つのアイテムをキューに保持します。その理由は、スレッドCが常に少なくとも1つのアイテムにアクセスできるようにするためです。
スレッドCのループは次のようになります。
while (threadsRunning)
{
System.Threading.Thread.Sleep(500); // Update twice per second
ProcessDataAndUpdateScreen(cq.ElementAt(cq.Count - 1)); // our terrible attempt at looking at the latest (or close to latest) entry in the queue
}
このループでは、データをディスクに書き込むスレッドとcq.ElementAt(cq.Count-1)呼び出しの間の競合が原因で、例外が発生することがあります。私は何が起こっているのかは次のとおりだと思います。
- cq.Countは、たとえば90と計算されます。
- その時点で、スレッドBはすでにループを開始しており、ディスクに書き込むためにキューからデータをデキューしています。
- cq.ElementAt()が呼び出されるまでに、スレッドBは、(cq.Count-1)がキュー内の有効なエントリを指さなくなるような多くのアイテムを消費しました。
キューで動作している複数のスレッドが存在する場合に、キュー内の最も若いエントリにアクセスするための優れた方法について何かアイデアはありますか?
よろしく、