問題タブ [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.

0 投票する
1 に答える
2921 参照

c++ - アトミックvs ミューテックスで保護されたブール

いくつかのスレッドがデータを書き込んでいるメモリ領域があると仮定しましょう。その後、別の場所に注意を向け、任意の他のスレッドがデータを読み取れるようにします。ただし、ある時点で、そのメモリ領域を再利用する必要があり、再度書き込みます。

ライター スレッドはブール フラグ ( valid) を提供します。これは、メモリがまだ有効であることを示します (つまり、まだ再利用されていません)。ある時点で、彼はこのフラグを false に設定し、二度と true に設定することはありません (1 回反転するだけです)。

シーケンシャルな一貫性により、次の 2 つのコード スニペットをライターとリーダーにそれぞれ使用するのが正しいはずです。

シーケンシャルな一貫性を確保するために何かをする必要があることは明らかです。つまり、必要な取得と解放のメモリ バリアを挿入します。データをセグメントに書き込む前に、書き込みスレッドでフラグを false に設定します。そして、チェックするにリーダー スレッドでデータをメモリから読み取る必要がありますvalid後者は、 valid が単調であることがわかっているためです。つまり、読み取りも有効である場合、読み取り中は有効でした。

メモリアクセスとアクセスの間に完全なフェンスを挿入すると、validうまくいきます。しかし、valid原子を作るだけで十分でしょうか?

それで

このシナリオでは、アトミック ストアと読み取りを使用した暗黙の解放操作と取得操作がうまく機能しないようです。ライターの RELEASE は、メモリ アクセスが上に移動することを妨げません(上記のコードだけが下に移動することはできません)。同様に、リーダーの ACQUIRE は、メモリ アクセスが下に移動することを妨げません(下のコードだけが上に移動しない場合があります)。

これが正しい場合、このシナリオを機能させるには、ライター スレッドで ACQUIRE (ロード) が必要であり、リーダー スレッドで RELEASE (ストア) が必要です。または、通常のブール値フラグを使用して、共有ミューテックスを使用してスレッド内の書き込みアクセスと読み取りアクセスを保護することもできます (それに対してのみ!)。そうすることで、両方のスレッドに ACQUIRE と RELEASE の両方を効果的に持つことがvalidでき、メモリ アクセスからアクセスを分離できます。

したがって、これは と で保護されatomic<bool>た通常の との間の非常に深刻な違いになります。これは正しいですか?boolmutex

編集:実際には、アトミックのロードとストアによって暗示されるものに違いがあるようです。std::atomicC++11のは、それぞれロードとストアmemory_order_seq_cstではなく両方 (!) を使用します。memory_order_acquirememory_order_release

対照的に、tbb::atomicではなくmemory_semantics::acquireandを使用します。memory_semantics::releasememory_semantics::full_fence

したがって、私の理解が正しければ、コードは標準の C++11 アトミックで正しくなりますが、tbb アトミックでは、明示的なmemory_semantics::full_fenceテンプレート パラメーターをロードとストアの両方に追加する必要があります。

0 投票する
4 に答える
777 参照

c++ - アトミック取得ロードの後に​​非アトミックロードを並べ替えることはできますか?

C++11以降で知られているように、6つのメモリ順序があり、ドキュメントには次のように書かれていstd::memory_order_acquireます:

memory_order_acquire

このメモリ順序での読み込み操作は、影響を受けるメモリ位置で取得操作を実行します。現在のスレッドのメモリ アクセスは、この読み込みの前に並べ替えることができません。これにより、同じアトミック変数を解放する他のスレッドでのすべての書き込みが、現在のスレッドで確実に表示されます。

1. 非アトミックロードは、アトミック取得ロードの後に​​並べ替えることができます。

つまり、acquire-atomic-load の後に non-atomic-load を並べ替えることができないという保証はありません。

の後にロードint local1 = L;を並べ替えることはできますX.load(std::memory_order_acquire);か?

2. 非アトミック ロードは、アトミック アクワイア ロードの後に​​並べ替えることができないと考えることができます。

一部の記事には、取得と解放のセマンティクスの本質を示す図が含まれていました。これは簡単に理解できますが、混乱を招く可能性があります。

ここに画像の説明を入力

ここに画像の説明を入力

たとえば、std::memory_order_acquire一連の Load-Load 操作を並べ替えることができないと考えるかもしれません。非アトミック ロードであっても、atomic-acquire-load の後で並べ替えることはできません。

3. 非アトミックロードは、アトミック取得ロードの後に​​並べ替えることができます。

明確化されていることは良いことです: セマンティクスを取得することで、プログラム順序でそれに続く読み取りまたは書き込み操作による読み取り/取得のメモリの並べ替えが防止されます。http://preshing.com/20120913/acquire-and-release-semantics/

しかし、次のことも知られています: 厳密に順序付けされたシステム ( x86、SPARC TSO、IBM メインフレーム) では、大部分の操作で解放と取得の順序付けが自動的に行われます。

また、34 ページの Herb Sutter には次のように示されています

ここに画像の説明を入力

4. つまり、atomic-acquire-load の後に non-atomic-load を並べ替えることはできないと考えることができます。

つまり、x86 の場合:

  • リリースと取得の順序付けは、ほとんどの操作で自動的に行われます
  • 読み取りは、どの読み取りでも並べ替えられません。(任意 - つまり、古いかどうかに関係なく)

では、C++11 でアトミック取得ロードの後に​​非アトミックロードを並べ替えることができますか?

0 投票する
0 に答える
83 参照

c# - System.Threading.Timer で使用される変数はキャッシュの対象ですか?

不可解に停止しているプロセスをトラブルシューティングしようとしています。また、変数がキャッシュされて二度と読み取れないという問題が発生する可能性があるかどうかを判断しようとしています。

私のシナリオでは、タイマーで発生する操作 (これを と呼びますPoll) と、外部操作の開始と停止を通知するために呼び出される外部関数のペアがあります。実際には詳細に入る価値がないため、この架空のクラスでは、外部操作が行われている場合に Poll 操作を実行したくありません。さらに、外部操作は同時に複数回発生する可能性があるため、進行中の操作の数を示すためにカウンターを使用しています。

現在のロジックは、次の単純化された例のように見えます。

仮定:

  • StartExternalOperationとの両方EndExternalOperationが同じ回数だけ呼び出されていtry...finallyます。Start
  • 不確定な回数の実行後のある時点で、DoSomething()再び呼び出されることはありません。私の実際のシナリオでは、正確な理由はわかりませんが、これ以外に見つけられるすべての原因を排除しました。

値がキャッシュされ、実際の変数が再度読み取られないという読み取り操作で、何らかの種類のフェンス (スルーInterlockedまたは変数)を使用していない可能性はありますか?volatile

これは確実に再現できない問題であるため、私が疑っているものが合理的に原因であるかどうかを知る必要があります. ReaderWriterLock(または)のようなより正式なものを使用するようにコードを変更することができ、Slim適切なロジックがあることはわかっています。説明したことが正当に原因であるかどうかを知る必要があります。

0 投票する
2 に答える
394 参照

c++11 - ロックフリー同期、フェンス、およびメモリ順序 (取得セマンティクスを使用したスト​​ア操作)

ベアボーンで実行されていたプロジェクトを Linux に移行しており、いくつかの{disable,enable}_scheduler呼び出しを削除する必要があります。:)

したがって、ライター スレッドをブロックできない単一のライター、複数のリーダーのシナリオでは、ロックのない同期ソリューションが必要です。次の解決策を思いつきましたが、これは通常の取得と解放の順序には適合しません。

意図が明確であることを願っています: (非アトミック) ペイロードの変更を でラップし、 にbeginWrite/endWrite渡されたラムダ関数内でのみペイロードを読み取りますsync()

ご覧のとおり、ストア操作後の書き込みをストアの前に並べ替えることができないアトミックストアがあります。beginWrite()適切な例が見つからず、この分野の経験がまったくないため、問題がないことを確認したいと思います(テストによる検証も容易ではありません)。

  1. このコードはレースフリーで、期待どおりに動作しますか?

  2. すべてのアトミック操作で std::memory_order_seq_cst を使用する場合、フェンスを省略できますか? (そうだとしても、パフォーマンスは悪くなると思います)

  3. endWrite() でフェンスをドロップできますか?

  4. フェンスで memory_order_acq_rel を使用できますか? 私には違いがよくわかりません。単一の合計注文の概念は私には明確ではありません。

  5. 簡素化/最適化の機会はありますか?

+1。このクラスの名前として、より良いアイデアを喜んで受け入れます:)