シングル プロデューサー スレッド、シングル コンシューマー スレッドのロックレス キューがあり、プロデューサーが長期間にわたってデータを生成しない場合があるとします。キューに何もないときにコンシューマー スレッドをスリープ状態にすることは有益です (電力を節約し、他のプロセス/スレッドのために CPU を解放するため)。キューがロックレスではない場合、この問題を解決する簡単な方法は、生成スレッドにミューテックスをロックさせ、その作業を実行させ、条件変数を通知してロックを解除し、読み取りスレッドがミューテックスをロックするまで条件変数を待機することです。 、その読み取りを行い、ロックを解除します。しかし、ロックレス キューを使用している場合、まったく同じ方法でミューテックスを使用すると、そもそもロックレス キューを使用することで得られるパフォーマンスが失われてしまいます。
単純な解決策は、キューへの挿入ごとにプロデューサーにミューテックスをロックさせ、条件変数を通知してからミューテックスのロックを解除し、実際の作業 (キューへの挿入) を完全にロックの外に保ち、コンシューマーに実行させることです。同じように、ミューテックスをロックし、条件変数を待機し、ロックを解除し、キューからすべてを取り出してから繰り返し、キューの読み取りをロックの外に保ちます。ただし、ここには競合状態があります。リーダーがキューから離れてからスリープ状態になるまでの間に、プロデューサーがアイテムをキューに挿入した可能性があります。これでリーダーはスリープ状態になり、プロデューサーが別のアイテムを挿入して条件変数に再度シグナルを送るまで、無期限にスリープ状態になる可能性があります。これは、特定のアイテムがキューを通過するのに非常に長い時間がかかるように見える場合があることを意味します. キューが常にアクティブである場合、これは問題にならない可能性がありますが、常にアクティブである場合は、条件変数を完全に忘れてしまう可能性があります。
AFAICT解決策は、プロデューサーが通常のニーズロックキューを使用しているかのように動作することです。ミューテックスをロックし、ロックレス キューに挿入し、条件変数を通知し、ロックを解除する必要があります。ただし、消費者は異なる行動を取る必要があります。起動すると、キューが読み取られるまで待機するのではなく、すぐにミューテックスのロックを解除する必要があります。次に、できる限り多くのキューをプルして処理する必要があります。最後に、消費者がスリープ状態になることを考えている場合にのみ、ミューテックスをロックし、データがあるかどうかを確認し、データがある場合はロックを解除して処理するか、そうでない場合は条件変数を待機します。この方法では、ロックフル キューよりもミューテックスの競合が少なくなりますが、キューにデータが残ったままスリープ状態になるリスクはありません。
これが最善の方法ですか?代替手段はありますか?
注: 「最速」とは、実際には「キューを何度もチェックするためにコアを専用にすることなく最速」を意味しますが、それはタイトルには当てはまりません;p
1 つの代替方法: 単純なソリューションを使用しますが、キューを通過するアイテムに対して許容できる最大待機時間に対応するタイムアウトを使用して、コンシューマーを条件変数で待機させます。ただし、必要なタイムアウトがかなり短い場合は、OS の最小待機時間を下回っているか、CPU の消費量が多すぎる可能性があります。