問題タブ [memory-barriers]
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++ - x86 での競合状態
誰かがこの声明を説明できますか:
x86 プロセッサr1 == 0
を使用するにはどうすればよいですか?r2 == 0
Bartosz Milewski によるソース「The Language of Concurrency」。
lock-free - スピンロックには常にメモリバリアが必要ですか? メモリバリアでのスピンは高価ですか?
ほとんどの条件下で、ローカル読み取りで問題なく動作するロックフリー コードをいくつか書きました。
メモリ読み取りでのローカル スピンは、スピン読み取りの前に常にメモリ バリアを挿入する必要があることを意味しますか?
(これを検証するために、特定の非常に特定の条件下で、リーダーが書き込まれた値をまったく見ないという結果になるリーダー/ライターの組み合わせを作成することに成功しました。ループ内で実行されるため、矢印はその方向を指していますが、メモリバリアを通過するコストについては完全にはわかりません.)
キャッシュのストア バッファにフラッシュするものが何もない場合、メモリ バリアを介してスピンするコストはいくらですか? つまり、すべてのプロセスが (C で) 行っているのは、
それは無料であり、メモリバスにトラフィックを邪魔しないと仮定するのは正しいですか?
別の言い方をすれば、次のように質問することです: メモリ バリアは、ストア バッファーをフラッシュし、無効化を適用し、コンパイラーがその場所全体で読み取り/書き込みを並べ替えないようにする以上のことを行いますか?
逆アセンブルすると、__sync_synchronize() は次のように変換されます。
Intelのマニュアルから(同様に、初心者にとっては漠然としています):
私の翻訳: 「ロックと言うと、これはコストがかかりますが、必要な場合にのみ行っています。」
@BlankXavier:
ライターがストア バッファーから書き込みを明示的にプッシュアウトせず、それがその CPU で実行されている唯一のプロセスである場合、リーダーはライターの効果を確認できない可能性があることをテストしました (テスト プログラムで再現できますが、上で述べたように、特定のコンパイルオプションと専用のコア割り当てを使用した特定のテストでのみ発生します-私のアルゴリズムは正常に機能します。将来の問題)。
デフォルトでは、単純な書き込みはWB書き込み(ライトバック)であると思います。つまり、すぐにはフラッシュされませんが、読み取りは最新の値になります(「ストア転送」と呼ばれると思います)。そこで、ライタには CAS 命令を使用します。Intelのマニュアルで、これらすべての異なるタイプの書き込み実装(UC、WC、WT、WB、WP)、Intel vol 3A chap 11-10を発見し、まだそれらについて学んでいます。
私の不確実性は読者の側にあります.McKenneyの論文から、バスからキャッシュへの受信無効化のキューである無効化キューもあることがわかりました。この部分がどのように機能するかわかりません。特に、通常の読み取りをループする(つまり、ロックされていない、バリアなしで、揮発性を使用して、コンパイル後にオプティマイザーが読み取りを確実に残すようにする)と、毎回「無効化キュー」にチェックインすることを暗示しているようです。 (そのようなものが存在する場合)。単純な読み取りでは不十分な場合 (つまり、キューに入れられた無効化が保留されている間はまだ有効に見える古いキャッシュ ラインを読み取ることができます (これは私にも少し矛盾しているように聞こえますが、無効化キューはどのように機能するのでしょうか?))、アトミック読み取りは次のようになります。私の質問は次のとおりです。この場合、これはバスに影響を与えますか? (多分無いと思います。)
私はまだ Intel のマニュアルを読んでいますが、ストア フォワーディングについては素晴らしい議論が見られますが、無効化キューについては適切な議論が見つかりませんでした。C コードを ASM に変換して実験することにしました。これがどのように機能するかを実際に理解するには、これが最善の方法だと思います。
c++ - ミューテックスロック機能は揮発性がなくても十分ですか?
同僚と私は、x86、x64、Itanium、PowerPC、およびその他の10年前のサーバーCPUで実行されているさまざまなプラットフォーム用のソフトウェアを作成しています。
pthread_mutex_lock()... pthread_mutex_unlock()などのミューテックス関数だけで十分かどうか、または保護された変数を揮発性にする必要があるかどうかについて話し合いました。
私の懸念はキャッシングです。コンパイラは_protectedのコピーをスタックまたはレジスタに配置し、その古い値を割り当てに使用できますか?そうでない場合、それが起こらないようにするものは何ですか?このパターンのバリエーションは脆弱ですか?
コンパイラはpthread_mutex_lock()が特殊関数であることを実際には理解していないと思いますが、シーケンスポイントによって保護されているだけですか?
どうもありがとうございました。
更新:わかりました。揮発性が悪い理由を説明する回答のある傾向を見ることができます。私はそれらの答えを尊重しますが、その主題に関する記事はオンラインで簡単に見つけることができます。私がオンラインで見つけることができないもの、そして私がこの質問をしている理由は、私が揮発性なしでどのように保護されているかです。上記のコードが正しければ、キャッシュの問題に対してどのように無防備になりますか?
c# - スレッドの同期。ロックはどの程度正確にメモリへのアクセスを「正しく」しますか?
まず第一に、私はそれがクラスlock{}
のための合成砂糖であることを知っています。Monitor
(ああ、糖衣構文)
私は単純なマルチスレッドの問題で遊んでいましたが、メモリの任意のWORDをロックすると、他のすべてのメモリがキャッシュされないようにする方法を完全に理解できないことがわかりました。レジスタ/ CPUキャッシュなどです。コードサンプルを使用して、私が言っていることを説明する方が簡単です。
結局、もちろん予想されるものms_Sum
が含まれます。100000000
ここで、同じサイクルを2つの異なるスレッドで実行し、上限を半分にしてエージングします。
同期がないため、誤った結果が得られます。私の4コアのマシンでは、ほぼ乱数で52 388 219
あり、の半分よりわずかに大きくなってい100 000 000
ます。で囲むms_Sum += 1;
とlock {}
、当然のことながら、絶対に正しい結果が得られます100 000 000
。しかし、私にとって興味深いのは(実際には、同じような動作を期待していたと言っている)、lock
前の行と後のms_Sum += 1;
行を追加すると、答えがほぼ正しくなることです。
この場合、私は通常ms_Sum = 99 999 920
、非常に近い値を取得します。
質問:なぜlock(ms_Lock) { ms_Counter += 1; }
プログラムを完全に正しくするのにlock(ms_Lock) {}; ms_Counter += 1;
、ほとんど正しくするのか。任意のms_Lock
変数をロックすると、メモリ全体がどのように安定しますか?
どうもありがとう!
PSマルチスレッドに関する本を読みに行きました。
同様の質問
memory-barriers - メモリ バリアと緩和されたメモリ モデル
現在、メモリバリア、ロック、およびメモリモデルの理解を深めようとしています。
私の知る限り、4 つの異なるタイプの緩和が存在します。名前は、書き込み -> 読み取り、書き込み -> 書き込み、読み取り -> 書き込み、読み取り -> 読み取りです。x86 プロセッサでは、Total Store Order (TSO) と呼ばれることが多い Write->Read 緩和のみが可能です。パーシャル ストア オーダー (PSO) ではさらに書き込み→書き込みの緩和が可能であり、緩和ストア オーダー (RSO) では上記のすべての緩和が可能です。
さらに、解放、取得、および両方の 3 種類のメモリ バリアが存在します。ロックは、バリアの取得と解放だけを使用することも、場合によっては完全なバリア (.Net) を使用することもできます。
次の例を考えてみましょう。
私の現在の理解では、このコードを TSO マシンで実行する場合、追加のメモリ バリアは必要ないことがわかります。PSO マシンの場合、フラグ =1 の場合にスレッド 1 が x の実際の値を確実に取得できるように、x=1 とフラグ = 1 の間にリリース バリアが必要です。RSO マシンの場合は、while(flag != 1); の間にさらに取得バリアが必要です。x を出力して、スレッド 1 が x の値を早期に読み取らないようにします。
私の観察は正しいですか?
c++ - pthread_cond_signal または pthread_cond_broadcast 呼び出しは、書き込みメモリ バリアを意味しますか?
条件変数は通常、参照する状態がミューテックスの下で変更されるように使用されます。ただし、状態が 1 つのセットのみのフラグである場合、同時実行を防ぐためにミューテックスは必要ありません。したがって、次のようなことをしたいかもしれません:
pthread_cond_broadcast
ただし、これは書き込みメモリ バリアを意味する場合にのみ安全です。そうしないと、待機中のスレッドは、フラグが書き込まれる前に条件変数のブロードキャストが表示される可能性があります。つまり、待機中のスレッドが目覚め、cvar シグナルを消費する可能性がありますが、まだフラグが表示されます0
。
だから、私の質問は次のとおりです。pthread_cond_broadcast
andpthread_cond_signal
呼び出しは、書き込みメモリバリアを意味しますか? もしそうなら、これは関連する POSIX (または他の) 仕様のどこで指定されていますか? この点については、仕様が不明確なようでした。
注: 実際には、これによりメモリ バリアが発生することは承知しています (Linux では、スレッドの起動は完全な CPU メモリ バリアを意味し、クロス ライブラリ関数呼び出しはコンパイラのメモリ バリアを意味するため)。しかし、私はここでスペックが保証するものに興味があります。
c# - 異なるCPUコアでのコンテキストスイッチとスレッドの実行
SOに関する別の質問から、次の簡単な方法が可能であることがわかりました。
ifとコンソール書き込みライン呼び出しの間でコンテキストスイッチが発生した場合、異なるCPUで実行される可能性があります。これは私にとってニュースなので、シングルスレッドコードを別のCPUに切り替えることができるのはいつか、上記のような単純なケースでなぜ意味があるのか疑問に思います。 ?
c - アウト オブ オーダー実行とメモリ フェンス
最新の CPU が順不同で実行できることは知っていますが、ウィキペディアで説明されているように、常に結果を順番どおりに破棄します。
「順不同のプロセッサは、これらの「スロット」を、準備ができている他の命令で時間内に埋め、最後に結果を並べ替えて、命令が通常どおりに処理されたように見せます。」
現在、マルチコア プラットフォームを使用する場合はメモリ フェンスが必要であると言われています。これは、アウト オブ オーダーの実行により、xの間違った値がここに出力される可能性があるためです。
ここで私の質問は、アウト オブ オーダー プロセッサ (私が想定するマルチコア プロセッサの場合はコア) は常に結果をイン オーダーで破棄するため、メモリ フェンスの必要性は何かということです。マルチコア プロセッサのコアは、他のコアからのリタイアした結果のみを認識しますか?それとも処理中の結果も認識しますか?
上記の例では、プロセッサ 2 が最終的に結果を破棄するとき、xの結果はfの前に来るはずですよね? 順不同の実行中に、 x の前に f を変更した可能性がありますが、 x の前にそれを廃止してはならないことはわかっていますよね?
結果のインオーダー リタイアとキャッシュ コヒーレンス メカニズムが整った今、なぜ x86 でメモリ フェンスが必要になるのでしょうか?
c++ - メモリモデルの順序と可視性?
これについての詳細を探してみました。mutex とアトミックに関する標準も読みましたが、それでも C++11 メモリ モデルの可視性の保証を理解できませんでした。私が理解していることから、ミューテックス BESIDE 相互排除の非常に重要な機能は、可視性を確保することです。また、一度に 1 つのスレッドだけがカウンターを増加させるだけでは十分ではありません。最後にミューテックスを使用したスレッドによって格納されたカウンターをスレッドが増加させることが重要です (議論するときに人々がこれについてこれ以上言及しない理由が本当にわかりませんミューテックス、多分私は悪い教師を持っていました:))。したがって、私が言えることから、アトミックは即時の可視性を強制しません: (boost::thread を維持し、c++11 スレッドとミューテックス ライブラリを実装した人から):
memory_order_seq_cst を使用したフェンスは、他のスレッドへの即時の可視性を強制しません (MFENCE 命令も同様です)。C++0x メモリの順序付け制約は、まさにそれです --- 順序付け制約です。memory_order_seq_cst 操作は全体の順序を形成しますが、すべてのスレッドで合意する必要があることと、他の順序制約に違反してはならないことを除いて、その順序に制限はありません。特に、スレッドが制約と一致する順序で値を参照する場合、スレッドはしばらくの間「古い」値を参照し続ける可能性があります。
そして、私はそれで大丈夫です。しかし、問題は、アトミックに関する C++11 の構造が「グローバル」であり、アトミック変数の一貫性のみを保証するものを理解するのに苦労していることです。特に、ロードとストアの前後にメモリフェンスが存在することを保証する次のメモリ順序のどれが(もしあれば)理解しています: http://www.stdthread.co.uk/doc/headers/atomic/memory_order. html
私が言えることから、 std::memory_order_seq_cst はメモリバリアを挿入しますが、他のものは特定のメモリ位置での操作の順序付けのみを強制します。
だから誰かがこれを片付けることができますか、多くの人が std::atomic を使用して恐ろしいバグを作っていると思います.espは、デフォルトを使用しない場合(std::memory_order_seq_cstメモリ順序付け)
2.私が正しければ、それはそれを意味しますこのコードでは、2 行目は冗長です。
3. do std::atomic_thread_fence には、非アトミック var で seq の一貫性を確保するために std::atomic_thread_fence(std::memory_order_seq_cst); を実行する必要があるという意味で、ミューテックスと同じ要件があります。ロード前と std::atomic_thread_fence(std::memory_order_seq_cst);
アフターストア?
4.は
に相当
ないと思いますが、確認したいと思います。
編集: 5.発砲をアサートできますか?
2 つのスレッドのみが存在します。
最初のスレッドの書き込み
2 番目のスレッドの読み取り