2

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)呼び出しの間の競合が原因で、例外が発生することがあります。私は何が起こっているのかは次のとおりだと思います。

  1. cq.Countは、たとえば90と計算されます。
  2. その時点で、スレッドBはすでにループを開始しており、ディスクに書き込むためにキューからデータをデキューしています。
  3. cq.ElementAt()が呼び出されるまでに、スレッドBは、(cq.Count-1)がキュー内の有効なエントリを指さなくなるような多くのアイテムを消費しました。

キューで動作している複数のスレッドが存在する場合に、キュー内の最も若いエントリにアクセスするための優れた方法について何かアイデアはありますか?

よろしく、

4

1 に答える 1

2

AB通信とAC通信の両方がキューを通過する必要がありますか?スレッドAが各エントリをキューに書き込み(Bが読み取り、ログに記録するため)、エントリを保存すると、揮発性プロパティのどこかにキューに入れられます。Cが最年少の要素を取得するたびに、そのプロパティから直接読み取ることができます。

編集:揮発性プロパティだけに依存するのではなく、実際にInterlocked.CompareExchange<T>(T, T)「最年少エントリ」プロパティを設定して読み取るために使用する必要があります。

于 2011-05-15T13:54:30.587 に答える