スレッドセーフ C 11 キュー: 偽のスレッド ウェイクアップを解決する
多面的なプロジェクトでは、複数のスレッドがファイルのリストを同時に処理します。各スレッドは処理のためにファイルをキューに追加できます。これはシームレスに動作し、競合状態を回避する必要があります。ただし、予期しないセグメンテーション違反がいくつか発生したため、その原因の調査が必要です。
FileQueue クラスは、ミューテックス (qMutex) と条件変数 (populatedNotifier) を使用して、スレッド間のキュー操作を調整します。スレッドがキューにファイルを追加するとき (エンキュー)、待機中のスレッドに信号を送り (populatedNotifier.notify_one())、スレッドがキューからファイルを取得するとき (デキュー)、キューにデータが追加されるのを待ちます (必要: PopulatedNotifier.wait_for()).
これらの予防策にもかかわらず、デキュー メソッド、特に if (...wait_for(lock, timeout) == std::cv_status:: 内でセグメンテーション フォールトが発生することがあります。 no_timeout) { } ブロック。コードを調べると、クラッシュ時にキューが空であることがわかります。 wait_for は通知されたときにのみ cv_status::no_timeout を返し、ファイルがキューに追加されたことを意味するため、この動作は逆説的です。
この不可解な障害はどのようにして発生するのでしょうか?
犯人: 偽のウェイクアップ
システムの割り込みや再スケジュールなど、プログラムの制御外の要因により、条件変数で「偽のウェイクアップ」が発生する可能性があることが判明しました。これが発生すると、監視対象の条件に実際の変化が発生していないにもかかわらず、スレッドが起動される可能性があります。
FileQueue デキュー メソッドでは、条件変数を使用して新しいファイルの到着を待機します。ただし、条件はロックの解放後にチェックされるため、スレッドがロックを再取得する前にキューが再び空になる可能性があります。その結果、条件は有効でなくなる可能性があります。
解決策: 逆条件とロック ガード
より堅牢な条件変数ベースのアプローチには、ループを再構築することが含まれます。 逆条件を使用し、操作全体を通じてロックを維持します:
<code class="cpp">while (q.empty()) { populatedNotifier.wait(lock); }</code>
ロックを解放する前に空のキューをチェックすることで、スレッドはクリティカルな期間中ずっと条件が有効であることを保証します。セクション。誤って目覚めた場合、スレッドは続行する前に状態を再チェックします。
代替実装: 非同期キューのテンプレート
スレッドセーフ キューの精神に基づいて実装の場合、代替ソリューションを提供するテンプレートを次に示します:
<code class="cpp">while (q.empty()) { populatedNotifier.wait(lock); }</code>
この実装では、ミューテックスと条件変数に加えて、条件 (空のキュー) がロック内でチェックされ、偽のウェイクアップが発生した場合に再評価されることを保証する while ループが使用されます。
以上が条件変数を使用しているにもかかわらず、スレッド セーフ C 11 キューでセグメンテーション フォールトが発生するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。