1

多数のワーカー スレッドがあり、誰がどのジョブを取得するかをスレッドが判断するのにかかる時間を避けたいとします。

各スレッドに番号/ID が関連付けられているとします。ジョブリストがあります。キュー内の各ジョブには、ThreadID が関連付けられています。

ThreadID
1          = Job Available
0          = Job Finished
> 1        = Active ==> ThreadID = ID of thread working on the job

スレッドがジョブで動作するために、リストをスキャンして最初の ThreadID = 1 を見つけ、そのジョブを実行しようとします。

このようにして、スレッドはジョブを消費します。(明らかに、彼らは眠り、適切に目覚める必要がありますが、今のところはすべて無視します)

問題は、2 つのスレッドが同時に同じジョブを処理しようとする可能性があることです。これは好ましくありません。

これを解決するには、各スレッドはそのスレッド ID をスレッド ID に割り当てるだけで済みます。これにより、スレッド ID の書き込み前に読み取りが行われない限り、他のスレッドがジョブで動作するのを防ぐことができます。

ThreadID      Thread 11         Thread 12            ....
1             ThreadID == 1?                         Job available
                                ThreadID == 1?       Job available
11            ThreadID = 11                          Try to take job
12                              ThreadID == 12       Try to take job
              ThreadID == 11?                        Job was taken by another thread
                                ThreadID == 12?      (If no other competing threads then thread 12 got the job)

この表が正しいかどうかはわかりませんが、2 つのスレッドが競合していることがわかります。どちらもジョブを持っていると思っていますが、実際に ThreadId に番号を持っているスレッドがジョブを取得しました (ThreadID に書き込む最後のスレッドになります)。

そのようなスキームはロックを必要とせず、安全だと思いますか? これは正しいです?

4

2 に答える 2

1

ConcurrentQueue<T>通常、ジョブのコレクションとジョブを処理する複数のスレッドがある場合は、ロックまたは.NET 4のようなより複雑なノンブロッキング メカニズムを使用して、ジョブをスレッドセーフ キューに入れます。

各スレッドは、キューからジョブを取得して処理します。スレッドが完全に処理できなかった場合に、ジョブをキューに戻すための何らかのメカニズムが必要です。

ただし、ジョブがスレッドによって処理されているとマークする方法を続行する場合は、それを行うのは簡単ですが、ロックを使用して、一度に 1 つのスレッドのみがジョブを変更するようにする必要があります。

于 2013-07-02T03:18:53.570 に答える
0

あなたが説明しているように、あなたの「比較-書き込み-比較」方法は十分ではないと思います。このケースを参照してください。

  Thread 0          Thread 1

reads <empty>
                  reads <empty> 
writes 0
reads 0
runs task
                  writes 1
                  reads 1
                  runs task

そのインターリーブでは、両方のスレッドが同じタスクを実行します。あなたの説明で何かを見逃しているかもしれませんが、あなたのアルゴリズムを正しく理解していれば、これはその健全性の矛盾であるはずです.

于 2013-07-02T06:00:07.867 に答える