私が理解している限り、mfence
はハードウェアのメモリバリアであり、asm volatile ("" : : : "memory")
はコンパイラのバリアです。ただし、mfenceの代わりにasm volatile ("" : : : "memory")
を使用できます。
私が混乱した理由は このリンク です
まあ、メモリバリアは、メモリの順序付けが弱いアーキテクチャでのみ必要です。 x86とx64には弱いメモリ順序はありません。 x86/x64では、すべてのストアにリリースフェンスがあり、すべてのロードに取得フェンスがあります。したがって、本当に必要なのはasm volatile ("" : : : "memory")
だけです。
IntelとAMDの両方の適切な概要、および関連する製造元の仕様への参照については、 http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-)を参照してください。 x86 /
一般に、「揮発性」のようなものはフィールドごとに使用され、そのフィールドへのロードとストアはネイティブにアトミックです。フィールドへのロードとストアがすでにアトミックである場合(つまり、問題の「操作」は単一のフィールドへのロードまたはストアであり、したがって操作全体がアトミックである)volatile
フィールド修飾子またはメモリバリアはx86/x64で必要です。それにもかかわらず、移植可能なコード。
アトミックではない「操作」になると、たとえば、ネイティブのWordより大きいフィールドにロードまたは保存するか、「操作」内の複数のフィールドにロードまたは保存します。これは、操作をatomicは、CPUアーキテクチャに関係なく必要です。 一般にこれは、ミューテックスのような同期プリミティブによって行われます。ミューテックス(私が使用したもの)にはメモリバリアが含まれているため、プロセッサの並べ替えなどの問題を回避できるため、メモリバリア命令を追加する必要はありません。私は通常、同期プリミティブを使用しないことを時期尚早な最適化と見なしています。しかし、時期尚早の最適化の性質はもちろん、時間の97%です:)
同期プリミティブを使用せず、マルチフィールド不変式を処理している場合、プロセッサがストアを並べ替えたり、異なるメモリロケーションにロードしたりしないようにするメモリバリアが重要です。
ここで、asm volatileで「mfence」命令を発行するのではなく、クロバーリストで「memory」を使用するという点で。私ができることから read
アセンブラー命令が予期しない方法でメモリにアクセスする場合は、破壊されたレジスターのリストに `memory 'を追加します。これにより、GCCはアセンブラー命令全体でレジスターにキャッシュされたメモリー値を保持せず、そのメモリーへのストアまたはロードを最適化しなくなります。
彼らが「GCC」と言い、CPUについて何も言及しない場合、これはコンパイラーのみに適用されることを意味します。 「mfence」の欠如は、CPUメモリの障壁がないことを意味します。結果のバイナリを分解することでこれを確認できます。 「mfence」命令が発行されない場合(ターゲットプラットフォームによって異なります)、CPUがメモリフェンスを発行するように指示されていないことは明らかです。
使用しているプラットフォームと実行しようとしていることに応じて、「より良い」またはより明確なものがあるかもしれません。
asm volatile ("" ::: "memory")
はコンパイラのバリアです。asm volatile ("mfence" ::: "memory")
はコンパイラのバリアであり、MFENCE
でもあります__sync_synchronize()
は、コンパイラのバリアおよび完全なメモリバリアでもあります。そのため、asm volatile ("" ::: "memory")
は、CPUが独立したデータ命令自体を並べ替えることを妨げません。指摘したように、x86-64には強力なメモリモデルがありますが、StoreLoadの並べ替えは引き続き可能です。アルゴリズムを機能させるために完全なメモリバリアが必要な場合は、__sync_synchronize
2つの並べ替えがあります。1つはコンパイラの並べ替え、もう1つはCPUの並べ替えです。
x86/x64には比較的強力なメモリモデルがありますが、x86/x64でStoreLoadの並べ替え(後でロードが以前のストアを渡す)が発生する可能性があります。 http://en.wikipedia.org/wiki/Memory_ordering を参照してください
asm volatile ("" ::: "memory")
はコンパイラのバリアにすぎません。asm volatile ("mfence" ::: "memory")
は、コンパイラバリアとCPUバリアの両方です。つまり、コンパイラバリアのみを使用します。コンパイラの並べ替えを防ぐことはできますが、CPUの並べ替えを防ぐことはできません。つまり、ソースコードのコンパイル時に並べ替えはありませんが、実行時に並べ替えが発生する可能性があります。
したがって、どちらを使用するかは、ニーズによって異なります。