std::atomic<T>
変数に対する操作のメモリ順序付けパラメーターは、その操作自体の順序付けには影響しません。操作が他の操作と作成する順序付けの関係に影響します。
たとえばa.store(std::memory_order_release)
、それ自体では、操作が他のものに関してどのように順序付けられているかについては何もわかりませんが、別のスレッドからa
の呼び出しとペアになっている場合、これは他の操作を順序付けます ---他の変数(非アトミック変数を含む) へのすべての書き込みが完了しますそのロードが格納された値を読み取る場合、ストアを実行したスレッドによって、ロードを実行したスレッドに表示されます。a.load(std::memory_order_acquire)
a
最新のプロセッサでは、操作の一部のメモリ順序付けは no-ops です。たとえば、x86 では、memory_order_acquire
、memory_order_consume
およびmemory_order_release
はロードおよびストア命令で暗黙的に指定され、個別のフェンスを必要としません。これらの場合、順序付けは、コンパイラが実行できる命令の並べ替えに影響を与えるだけです。
明確化: 命令内の暗黙的なフェンスは、すべてのメモリ順序制約がアトミック変数の個々の操作に関連付けられている場合、コンパイラが明示的なフェンス命令を発行する必要がないことを意味します。すべてに使用memory_order_relaxed
し、明示的なフェンスを追加する場合、コンパイラはそれらのフェンスを命令として明示的に発行する必要があります。
たとえば、x86 では、XCHG
命令は暗黙のmemory_order_seq_cst
フェンスを伴います。したがって、x86 では、以下の 2 つの交換操作に対して生成されたコードに違いはありません。どちらも単一のXCHG
命令にマップされます。
std::atomic<int> ai;
ai.exchange(3,std::memory_order_relaxed);
ai.exchange(3,std::memory_order_seq_cst);
ただし、次のコードで明示的なフェンス命令を取り除くコンパイラはまだ知りません。
std::atomic_thread_fence(std::memory_order_seq_cst);
ai.exchange(3,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
最終的にはコンパイラがその最適化を処理することを期待していますが、暗黙のフェンスがより良い最適化を可能にする同様のケースが他にもあります。
また、変数の直接操作にのみstd::memory_order_consume
適用できます。