Looking for c++ Answers? Try Ask4KnowledgeBase
Looking for c++ Keywords? Try Ask4Keywords

C++C ++ 11メモリモデル


備考

少なくとも1つの操作が修正( ストア操作としても知られている)である場合、同じメモリ位置にアクセスしようとする異なるスレッドがデータ競合に参加する。これらのデータ競合は未定義の動作を引き起こします 。それらを回避するには、これらのスレッドがこのような競合する操作を同時に実行するのを防ぐ必要があります。

同期プリミティブ(ミューテックス、クリティカルセクションなど)は、そのようなアクセスを保護することができる。 C ++ 11で導入されたメモリモデルは、マルチスレッド環境でメモリへのアクセスを同期させる2つの新しい移植可能な方法を定義しています。アトミック操作とフェンスです。

アトミックオペレーション

アトミック・ロードおよびアトミック・ストア操作を使用することにより、所定のメモリー位置を読み書きすることが可能になりました。便宜上、これらはstd::atomic<t>テンプレートクラスにラップされています。このクラスはt型の値をラップしますが、今回はオブジェクトへのロードストアはアトミックです。

テンプレートはすべてのタイプで使用できるわけではありません。利用可能なタイプは実装固有ですが、これには通常、利用可能な大部分(またはすべて)の整数タイプとポインタタイプが含まれます。したがって、 std::atomic<unsigned> std::atomic<std::pair<bool,char>>ほとんど使用されませんが、 std::atomic<unsigned>std::atomic<std::vector<foo> *>は使用可能になります。

アトミック操作には、次のプロパティがあります。

  • すべてのアトミック操作は、未定義の動作を引き起こすことなく、複数のスレッドから同時に実行できます。
  • アトミック・ロードは、アトミック・オブジェクトが構築された初期値、または何らかのアトミック・ストア操作を介してアトミック・オブジェクトに書き込まれた値のいずれかを示します。
  • 同じ原子オブジェクトへのアトミックストアは、すべてのスレッドで同じ順序になります。あるスレッドがすでに何らかのアトミックストア操作の値を見ている場合、その後のアトムロード操作では、同じ値、またはそれ以降のアトミックストア操作によって格納された値が表示されます。
  • アトミックなリード・モディファイ・ライト・オペレーションにより、 アトミック・ロードアトミック・ストアは 、他のアトミック・ストアを介さずに実行できます 。たとえば、複数のスレッドからカウンタをアトミックにインクリメントすることができ、スレッド間の競合に関係なくインクリメントは失われません。
  • アトミック操作は、オプションのstd::memory_orderパラメーターをstd::memory_orderます。このパラメーターは、操作が他のメモリー位置に関してどのような追加プロパティーを持つかを定義します。
std :: memory_order 意味
std::memory_order_relaxed 追加の制限なし
std::memory_order_releasestd::memory_order_acquire load-acquirestore-releaseによって格納された値を確認した後、 store-release発生する前にシーケンスが store-releaseされてからload-acquireされた後にロードが順序付けされる
std::memory_order_consume memory_order_acquireようなものmemory_order_acquireが、依存負荷の場合のみです
std::memory_order_acq_rel load-acquirestore-release組み合わせる
std::memory_order_seq_cst 逐次整合性

これらのメモリオーダータグでシーケンシャル一貫性リラックス 、および兄弟リリースでのリリース 取得消費 される 、3つの異なるメモリオーダリング規律が可能です。

シーケンシャル一貫性

アトミック操作にメモリー順序が指定されていない場合、順序はデフォルトで順次整合性になります。このモードは、 std::memory_order_seq_cstオペレーションをタグ付けすることで明示的に選択することもできます。

この順序では、メモリ操作はアトミック操作を通過できません。すべてのメモリ操作は、アトミック操作がアトミック操作およびアトミック操作が発生する前に、アトミック操作が発生する前に順次行われ、その後に順序付けられたすべてのメモリ操作が行われます。このモードはおそらく最も簡単なものですが、パフォーマンスに最大の不利益をもたらします。また、アトミック操作を超えて操作を並べ替えることを試みる可能性のあるすべてのコンパイラーの最適化を防止します。

リラックスオーダー

シーケンシャル一貫性の逆は、 緩やかなメモリ順序付けである。これはstd::memory_order_relaxedタグで選択されます。緩和されたアトミック操作は、他のメモリ操作に制限を課さない。残っている唯一の効果は、操作自体が依然として原子的であることです。

リリースを取得する注文

アトミックストア操作にはstd::memory_order_releaseタグをstd::memory_order_releaseことができ、 アトミックロード操作にはstd::memory_order_acquireタグを付けることができます。最初の操作は(アトム)ストア・リリースと呼ばれ、2番目の操作は(アトム)ロード・アクティブと呼ばれます。

load-acquirestore-releaseによって書き込まれた値見ると、 store-releaseロード取得の 前に目に見えるようになるすべてのストア操作が、 ロード取得後に順序付けられたロード操作表示されます。

アトミックリードモディファイライトオペレーションは、累積タグstd::memory_order_acq_relも受け取ることができます。これにより、操作の原子負荷部分は原子のロードを獲得し、 原子ストアの部分は原子ストアの解放になります。

コンパイラーは、 アトミック・ストア・リリース操作後にストア操作を移動することはできません。また、 アトミックなロード取得 (またはロード消費 )の前に、ロード操作を移動することもできません。

原子のロード・リリースアトミック・ストア・アクセスがないことにも注意してください。このような操作を作成しようとすると、操作が緩和されます。

リリース - 注文を消費する

この組み合わせはrelease-acquireと似ていますが、今回は原子負荷に std::memory_order_consumeタグが付けられ、 (原子的な)負荷消費操作になります。このモードは、 load-consumeによってロードされた値に応じてロードを消費した後に順序付けられたロード操作のうち、順序付けられたロード操作の中では、 release-acquireと同じです。

フェンス

フェンスはまた、メモリ操作がスレッド間で順序付けられることを可能にする。フェンスはリリースフェンスまたはフェンスを取得します。

獲得フェンスの前にリリースフェンスが発生した場合、獲得フェンスの後にシーケンスされたロードにリリースフェンスが表示される前に順序付けられたストアが格納されます。獲得フェンスの前にリリースフェンスが発生することを保証するために、緩和された原子操作を含む他の同期プリミティブを使用することができる。

C ++ 11メモリモデル 関連する例