複数のスレッドがデータを生成し、単一のスレッドがデータを消費するシステムをモデル化しようとしています。秘訣は、すべてのスレッドがプールに存在するため、専用スレッドでデータを消費したくないということです。代わりに、作業があるときにプロデューサーの 1 つがキューを空にし、別のプロデューサーが既にキューをクリアしている場合は降伏するようにします。
基本的な考え方は、作業のキューと、処理の周りのロックがあるということです。各プロデューサーはペイロードをキューにプッシュし、ロックに入ろうとします。この試行は非ブロッキングであり、true (ロックが取得された) または false (ロックが他の誰かによって保持されている) を返します。
ロックが取得されると、そのスレッドはキュー内のすべてのデータを空になるまで処理します (処理中に他のプロデューサーによって導入された新しいペイロードを含む)。すべての作業が処理されると、スレッドはロックを解除して終了します。
以下は、アルゴリズムの C++ コードです。
void Process(ITask *task) {
// queue is a thread safe implementation of a regular queue
queue.push(task);
// crit_sec is some handle to a critical section like object
// try_scoped_lock uses RAII to attempt to acquire the lock in the constructor
// if the lock was acquired, it will release the lock in the
// destructor
try_scoped_lock lock(crit_sec);
// See if this thread won the lottery. Prize is doing all of the dishes
if (!lock.Acquired())
return;
// This thread got the lock, so it needs to do the work
ITask *currTask;
while (queue.try_pop(currTask)) {
... execute task ...
}
}
一般的に、このコードは正常に動作し、以下で説明する動作を実際に目撃したことはありませんが、その実装には不安を感じます。スレッドが while ループを終了してからクリティカル セクションを解放するまでの間に競合状態が発生するのは当然のことです。
アルゴリズム全体は、ロックが保持されている場合、スレッドがキューを処理しているという前提に依存しています。
私は本質的に2つの質問についての啓発を探しています:
- 説明されているように競合状態があることを訂正しますか (他のレースのボーナス)
- このメカニズムを実装するためのパフォーマンスが高く、競合状態を引き起こさない標準パターンはありますか?