9

このhttps://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.htmlMOVによると、リリースされたストアはx86 (x86-64 を含む) で (メモリに)実装されます。

彼のhttp://en.cppreference.com/w/cpp/atomic/memory_orderによると

memory_order_release :

このメモリ順序でのストア操作は、解放操作を実行します。現在のスレッド内のメモリ アクセスは、このストアの後に順序を変更することはできません。これにより、現在のスレッドのすべての書き込みが、同じアトミック変数を取得する他のスレッドで可視になり、アトミック変数への依存関係を運ぶ書き込みが、同じアトミックを消費する他のスレッドで可視になることが保証されます。

memory_order_releaseを使用する場合、以前に行われたすべてのメモリ ストアは、この前に終了する必要があることを理解しています。

int a;
a = 10;
std::atomic<int> b;
b.store(50, std::memory_order_release); // i can be sure that 'a' is already 10, so processor can't reorder the stores to 'a' and 'b'

質問:MOVむき出しの命令 (明示的なメモリ フェンスなし) でこの動作に十分であるとはどのように考えられるのでしょうか? MOV前のすべてのストアを終了するようプロセッサに指示するにはどうすればよいですか?

4

2 に答える 2

6

実行時に (CPU によって行われる) メモリの並べ替えがあり、コンパイル時にメモリの並べ替えがあります。詳細については、コンパイル時の並べ替えに関する Jeff Preshing の記事(およびそのブログの他の多くの優れた記事)をお読みください。

memory_order_releaseコンパイラがデータへのアクセスを並べ替えたり、必要なフェンシングや特別な命令を発行したりするのを防ぎます。x86 asm では、通常のロードとストアには既に取得/解放セマンティクスがあるため、acq_rel ではコンパイル時の並べ替えをブロックするだけで十分ですが、seq_cst では十分ではありません。

于 2015-04-28T15:57:26.970 に答える
5

少なくとも Intel コンパイラでコンパイルされたコードでは、マッピングのように見えます。

0000000000401100 <_Z5storeRSt6atomicIiE>:
  401100:       48 89 fa                mov    %rdi,%rdx
  401103:       b8 32 00 00 00          mov    $0x32,%eax
  401108:       89 02                   mov    %eax,(%rdx)
  40110a:       c3                      retq
  40110b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

0000000000401110 <_Z4loadRSt6atomicIiE>:
  401110:       48 89 f8                mov    %rdi,%rax
  401113:       8b 00                   mov    (%rax),%eax
  401115:       c3                      retq
  401116:       0f 1f 00                nopl   (%rax)
  401119:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

コードの場合:

#include <atomic>
#include <stdio.h>

void store( std::atomic<int> & b ) ;

int load( std::atomic<int> & b ) ;

int main()
{
   std::atomic<int> b ;

   store( b ) ;

   printf("%d\n", load( b ) ) ;

   return 0 ;
}

void store( std::atomic<int> & b )
{
   b.store(50, std::memory_order_release ) ;
}

int load( std::atomic<int> & b )
{
   int v = b.load( std::memory_order_acquire ) ;

   return v ;
}

現在のIntel アーキテクチャ ドキュメント、ボリューム 3 (システム プログラミング ガイド) は、これをうまく説明しています。見る:

8.2.2 P6 以降のプロセッサ ファミリでのメモリの順序

  • 読み取りは、他の読み取りと並べ替えられません。
  • 書き込みは古い読み取りで並べ替えられません。
  • メモリへの書き込みは、次の例外を除いて、他の書き込みと並べ替えられません: ...

そこには完全なメモリモデルが説明されています。Intel と C++ 標準の関係者が詳細に協力して、第 3 巻で説明されているメモリ モデルに準拠し、可能なメモリ順序操作のそれぞれに最適なマッピングを特定し、プレーン ストアとロードが決定されたと思います。そのような場合には十分です。

x86-64 でこの順序付きストアに特別な指示が必要ないからといって、それが普遍的に当てはまるわけではないことに注意してください。powerpc の場合、ストアと共に lwsync 命令のようなものが表示されると予想されます。hpux (ia64) では、コンパイラは st4.rel 命令を使用する必要があります。

于 2015-04-28T15:48:53.277 に答える