単一プロデューサスレッドのシングルコンシューマスレッドのロックレスキューがあり、プロデューサがデータを生成することなく長期間使用する可能性があるとします。待ち行列に何もないときにコンシューマースレッドをスリープさせることは有益です(節電と他のプロセス/スレッドのためのCPUの解放)。キューがロックレスでない場合、この問題を解決する簡単な方法は、生成スレッドがミューテックスをロックし、その作業を行い、条件変数を通知してロックを解除し、読み取りスレッドがミューテックスをロックするために、それを読んでから、ロックを解除してください。しかし、ロックレスキューを使用している場合は、ミューテックスを使用すると全く同じ方法で、まずロックレスキューを使用することで得られるパフォーマンスがなくなります。ロックレスキューをポーリングするための最速レースフリーメソッドは何ですか?
純粋な解決策は、キューに挿入するたびにプロデューサがミューテックスをロックし、条件変数に信号を送り、ミューテックスをロック解除し、実際の作業(キューへの挿入)を完全にロックの外に保ち、消費者に同じことをさせて、mutexをロックし、条件変数を待って、ロックを解除し、すべてをキューから引き出し、繰り返して、ロックの外にあるキューの読みを保持します。ここには競合状態があります。読者が待ち行列から抜け出して寝る間に、プロデューサーがアイテムを待ち行列に挿入した可能性があります。今度は読者が眠りにつき、プロデューサーが別の商品を挿入して再び条件変数に信号を送るまで無期限に滞在することがあります。これは、キューを通過するのに非常に時間がかかるような特定のアイテムで時々終わることがあることを意味します。あなたのキューが常に常時アクティブである場合、これは問題ではないかもしれませんが、常にアクティブだった場合は、条件変数を完全に忘れる可能性があります。
AFAICT解決策は、プロデューサが通常のニーズロックキューを使用している場合と同じように動作することです。ミューテックスをロックし、ロックレスキューに挿入し、条件変数を通知し、ロックを解除する必要があります。しかし、消費者は異なる行動をとるべきです。起動すると、キューを読み取るまで待つのではなく、すぐにmutexのロックを解除する必要があります。次に、できるだけ多くのキューをプルして処理する必要があります。最後に、消費者がスリープ状態に入ることを考えているときにのみ、ミューテックスをロックし、データがあるかどうかを確認し、アンロックして処理するか、そうでなければ条件変数を待ちます。このようにして、ミューテックスはlockfullキューより少ない頻度で競合しますが、まだキューに残っているデータでスリープするリスクはありません。
これを行う最も良い方法ですか?代わりがありますか?
注:「最速」とは、私は本当に「何度もキューをチェックするコアを捧げることなく、最速」を意味するが、それがタイトルに収まらない; P
1つの代替:素朴な解決方法を試してみましょうが、コンシューマは、キューを通過するアイテムに対して許容する最大レイテンシに対応するタイムアウトを条件変数に設定します。ただし、希望のタイムアウトがかなり短い場合は、ご使用のOSの最小待ち時間を下回っている場合や、CPUが多すぎる場合があります。
プロデューサーが何かを生産するたびに条件変数に信号を送ることはできませんか?なぜミューテックスが必要なのでしょうか? – Gabe
@ギャベ:2つの理由。第1に、この場合、プロデューサは何かを生成し、消費者がアイテムの処理を終えたときと条件変数を待つことを決定したときとの間で信号を発する可能性があるからです。その後、消費者は眠りにつき、プロデューサーが作ったアイテムは次回信号が発せられるまで待ち行列に留まります。第2に、少なくともpthreads APIでは、mutexなしで条件変数を使用することができないためです。あなたは実際にmutexをwait関数に渡す必要があります。条件変数のすべての実装が実際にそれらを必要としているかどうかはわかりません。 –
@Gabe:条件変数を待っているものが何もないときに信号が発せられたとき、次回に何かが条件変数を待つときに即座に目覚めてしまうが、その事件は起こらない。信号が発せられたときに条件変数を待っていなければ、それは決して起こったことはありません。この意味で、条件変数を待つことは、ファイル/ソケット/パイプでpoll/selectを使うこととは異なります。 –