平行キュークラス#
テンプレート・クラス concurrent_queue<T,Alloc> は、T タイプの値を持つ並行キューを実装します。複数スレッドがキューから要素を同時にプッシュおよびポップします。キューは無制限であり、ブロッキング操作はありません。基本的な操作は push と try_pop です。push 操作は、std::queue の push と同じように機能します。try_pop 操作は、利用可能な場合に項目をポップします。スレッドの安全性を確保するため、チェックとポップは単一の操作で実行する必要があります。
例えば、次のシリアルコードについて考えてみます。
extern std::queue<T> MySerialQueue;
T item;
if( !MySerialQueue.empty() ) {
item = MySerialQueue.front();
MySerialQueue.pop_front();
... 項目を処理...
}各 std::queue メソッドがスレッドセーフな方法で実装されていても、同じキューからポップする他のスレッドがある場合、例に示されるメソッドの構成はスレッドセーフではありません。例えば、MySerialQueue.empty() は、別のスレッドが MySerialQueue から最後の項目を取得する直前に true を返す場合があります。
同等のスレッドセーフな oneAPI スレッディング・ビルディング・ブロック (oneTBB) のコードは次のとおりです。
extern concurrent_queue<T> MyQueue;
T item;
if( MyQueue.try_pop(item) ) {
...項目を処理...
}シングルスレッド・プログラムでは、キューは FIFO (先入れ先出し) 構造です。しかし、マルチスレッド・プログラムの場合、プッシュとポップが同時に行われるため、“先入れ” の定義は不確定です。Concurrent_queue を使用すると、スレッドが 2 つの値をプッシュし、別のスレッドがその 2 つの値をポップした場合、プッシュされた順番でポップされることが保証されます。
テンプレート・クラス concurrent_queue は無制限であり、待機するメソッドを持ちません。オーバーフローを回避するため同期を行うか、キューが空でなくなるまで待機するのはユーザーの責任です。通常、この方法は、同期を上位レベルで行う場合に適しています。
テンプレート・クラス concurrent_bounded_queue<T,Alloc> は、ブロッキング操作と容量を指定する機能を持つバリアントです。特に興味深いメソッドは次のとおりです。
pop(item)は、成功するまで待機します。push(item)は、キューの容量を超えずに成功するまで待機します。try_push(item)は、キューの容量を超えない場合にのみitemをプッシュします。size() は符号付き整数を返します。
concurrent_queue::size() の値は、開始されたプッシュ操作の数からポップ操作の数を引いたものとして定義されます。ポップ数がプッシュ数を上回ると size() は負になります。例えば、concurrent_queue が空で、保留中のポップ操作が n 個ある場合、size() は -n を返します。この方法を使用すると、生産タスクは、キュー上で待機している消費タスクの数を簡単に知ることができます。メソッド empty() は、size() が正でない場合にのみ true になるように定義されます。
デフォルトでは、concurrent_bounded_queue は無制限です。メモリーがなくなるまで、任意の数の値を保持します。set_capacity メソッドを使用してキューの容量を設定することで有限にできます。容量を設定すると、キューに空きができるまで push がブロックされます。制限のあるキューは無制限のキューよりも遅いため、キューの大きさを監視するようなコードがプログラム中にある場合は、大きさを設定しないほうがよいでしょう。制限またはブロッキング・ポップが必要ない場合は、代わりに concurrent_queue の使用を検討してください。