1

これが新しい問題ではないことはわかっていますが、C++11 メモリ フェンスについて読んだ後、混乱しました。

1 つのリーダー スレッドと 1 つのライター スレッドがあるとします。
普通に使えますintか?

    int x = 0; // global
writer    reader
x = 1;    printf("%d\n", x);

この動作は未定義ですか?
リーダー スレッドで未定義の値を取得できますか? または、 or ?
を使用するようなものです。したがって、値は最終的にリーダースレッドに到達します。std::atomic_uint_fast32_tstd::atomic<int>

    std::atomic<int x = 0; // global
writer                                    reader
x.store(1, std::memory_order_relaxed);    printf("%d\n", x.load(std::memory_order_relaxed));

答えは使用しているプラ​​ットフォームによって異なりますか? (たとえばx86)、通常のロード/ストアintは1つのCPU命令ですか?

両方の動作が似ている場合、両方のタイプで同じパフォーマンスを期待できますか?

4

2 に答える 2

5

要するに、intマルチスレッド環境で共有するプレーンを決して使用しないでください。

問題は CPU だけではなく、コンパイラのオプティマイザーです。gcc は次のようなコードを最適化できます (そしてそうします):

while(i == 1) {}if(i==1) { while(1) {} }。一度変数をチェックすると、値を再度リロードする必要はありません。これは、半分書き込まれた値が表示されるという他のすべての問題とは別の問題です (これは通常、x86 int では発生しません)。

の影響を測定することatomicは非常に困難です。多くの場合、CPU はアクセスを高度に最適化できますが、他の場合ははるかに遅くなります。実際にベンチマークする必要があります。

于 2016-06-02T21:50:10.907 に答える
2

アトミックを使用すると、コンパイラと CPU レベルの両方で効果があります。コメントが示唆するように、常にアトミックを使用する必要があります。そうしないと、コンパイラと CPU が共謀して、コードに対してクレイジーで非直感的な変換を実行し、合理的に期待することを行わないようにします。

あなたの質問の 2 番目の部分はより微妙です - ネイキッド int の代わりにアトミックを使用することのペナルティは何ですか? もちろん、これはコンパイラと CPU に大きく依存しますが、しばらくの間、コンパイラが「スマート」であり、Intel CPU を使用していると仮定しましょう。賢明なことに、すべてのアクセスをミューテックス ブロックにラップするだけでなく、アトミックのすべての要件を確実に満たしますが、パフォーマンスは最適ではありません。Intel CPU では、ストア/ロードの可視性に関する組み込みの保証があり、コンパイラが特別な命令なしで正しいことを実行しやすくなります。「通常の」動作IA64 メモリ順序付けを最適化する必要はありません。これはすべてのケースをカバーしているわけではありませんが、「リラックスした一貫性」のケースを扱っています。メモリ フェンシングの手順

一貫性が緩和されたケースでは、フェンス命令を生成する必要がないため、Intel に CPU レベルのペナルティはありません。ほとんどのペナルティは、より強力な一貫性が必要な場合に発生します (スピンロックを実装する場合や、発行順序が重要なロックフリーアルゴリズムを作成する場合など)。これらは、インターロックされた命令、フェンス命令、またはバスロック プレフィックスのいずれかになり、重大なペナルティが発生する可能性があります。

于 2016-06-02T23:42:58.423 に答える