問題タブ [memory-fences]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - コンパイラのみのメモリ バリア (std::atomic_signal_fence など) が役立つのはいつですか?
コンパイラ フェンスの概念は、メモリ モデル、バリア、順序付け、アトミックなどについて読んでいるときによく出てきますが、通常は、予想どおり、 CPU フェンスとも対になっているという文脈にあります。
ただし、ときどき、コンパイラにのみ適用されるフェンス構造について読むことがあります。この例は、 cppreference.comstd::atomic_signal_fence
で述べられている C++11 関数です。
std::atomic_signal_fence は std::atomic_thread_fence と同等ですが、メモリ順序付けのための CPU 命令は発行されません。コンパイラによる命令の並べ替えのみが、順序命令として抑制されます。
このトピックに関連する 5 つの質問があります。
名前
std::atomic_signal_fence
が示すように、非同期割り込み(スレッドがシグナル ハンドラーを実行するためにカーネルによってプリエンプトされるなど) は、コンパイラのみのフェンスが役立つ唯一のケースですか?その有用性は、 などの強く順序付けられたものを含むすべてのアーキテクチャに適用され
x86
ますか?コンパイラのみのフェンスの有用性を実証するために、具体的な例を提供できますか?
を使用する場合、使用と注文
std::atomic_signal_fence
の違いはありますか? (違いはないと思います。)acq_rel
seq_cst
この質問は最初の質問でカバーされるかもしれませんが、とにかくそれについて具体的に尋ねるのに十分興味があります:アクセスでフェンスを使用する必要はありますか? (もしそうなら、私はコンパイラーのみのフェンスが最適なツールになること
thread_local
を期待します。)atomic_signal_fence
ありがとうございました。
c++ - CPU レジスタがガベージ コレクターのルートのように機能するのはなぜですか?
CPU レジスタがガベージ コレクターのルートのように機能するのはなぜですか? ミューテーターが一時停止すると、ガベージ コレクターがルートをスキャンできるようになり、変数の内容が (メモリ フェンスを使用して) メモリにフラッシュされるため、レジスタにはメモリにないデータが含まれません...私の理解が正しければ...
では、なぜそれらをスキャンする必要があるのでしょうか? 私はこれを冗長性と見なしています...
c - C11 メモリ フェンスの使用状況
単純な 2 スレッド通信の例であっても、これを C11 アトミックおよび memory_fence スタイルで表現して適切なメモリ順序を取得するのは困難です。
共有データ:
プロデューサー スレッド:
消費者スレッド:
私が理解している限り、上記のコードは、store-in-bucket -> flag-store -> flag-load -> load-from-bucket を適切に順序付けます。ただし、バケットからのロードと新しいデータでのバケットの再書き込みの間に競合状態が残っていると思います。atomic_thread_fence()
バケットの読み取りに続く順序を強制するには、バケットの読み取りと次のatomic_storeの間に明示的なものが必要になると思います。残念ながらmemory_order
、memory_order_seq_cst
.
本当に汚い解決策は、消費者スレッドでダミー値を再割り当てbucket
することです。これは、消費者の読み取り専用の概念と矛盾します。
古い C99/GCC の世界では、__sync_synchronize()
十分に強力であると信じている従来型を使用できました。
このいわゆる反依存性を同期させるための、より優れた C11 スタイルのソリューションは何でしょうか?
(もちろん、そのような低レベルのコーディングを避け、利用可能な高レベルの構造を使用する必要があることは承知していますが、理解したいと思います...)
c++ - ビジー待機に揮発性ブール変数を使用する
別の開発者によって書かれたいくつかのコードを読んだ後に疑問が生じたので、調査を行ったところ、Andrei Alexandrescu の記事を見つけました。彼の記事では、忙しい待機のために揮発性ブール変数を使用することが可能であると述べています (待機/ウェイクアップの最初の例を参照してください)。
私はそれがどのように機能するのか本当にわかりません。
- volatile は、操作がアトミックであることを保証しません。実際には、ブール変数への読み取り/書き込みはアトミックですが、理論はそれを保証しません。私の観点からすると、上記のコードは、std::atomic::load/store 関数を使用して、それに応じてメモリの順序付け制約を取得/解放することにより、C++11 で安全に書き直すことができます。
- 説明した例ではこの問題はありませんが、複数の書き込みがある場合、メモリの順序付けに問題が発生する可能性があります。揮発性はフェンスではなく、メモリの順序付けを強制するものではなく、コンパイラの最適化を妨げるだけです。
では、なぜ多くの人が忙しい待機に volatile bool を使用し、それは本当に移植性があるのでしょうか?
c# - .Net メモリの可視性の動作
編集:私はついにこの問題に関する完全な記事を書きました:同期、メモリの可視性、漏れやすい抽象化
このコードを使用して、揮発性読み取りの重要性を示しています。
予想どおり、スレッドは新しいok
値を認識せず、プログラムがハングします。
while
しかし、この動作を実現するには、整数をインクリメントするなど、ループ内で何かを行う必要があります。
ステートメントを削除する++n
と、スレッドは新しい値を読み取って終了します。
CILに関する限り(少なくとも私のような素人にとっては)何もないため、 JITterの最適化と関係があると思います。
逆に、ループ内で何かを実行すると、スレッドがキャッシュの更新をトリガーする可能性が高くなると単純に予想できます。
私は再び何が欠けていますか?
最終編集: これもJITterの黒魔術です。
これが「よく知られた」JITter「問題」であることを確認し、x64では「期待される」動作が得られることを指摘してくれた Hans に感謝します。
結果のアセンブリ コードを提供し、デバッグの知恵を共有してくれたMagnatLUに感謝します。
gcc - なぜ同期バリアが必要なのですか?
共有メモリの場所に対して読み取り/書き込みを行う 2 つの pthread があります。1 つのスレッドで、メモリ ロケーションの更新をチェックし続けます。(Linux、Glibc)
スレッド 1:
スレッド 2:
ここでのポイントは、しばらく経っても更新が反映されていないことです。次のように同期バリアを使用すると、更新がすぐに表示されます。
だから私の質問は:
- しばらくたってもアップデートが表示されないのはなぜですか?
- __sync_synchronize() は正確には何をしますか?
編集 1: 更新がすぐに表示されない理由を理解しています。私の質問は、具体的には、非常に長い間表示されていない理由です。