C ++はintAtomicの読み取りと書き込みですか?


81

2つのスレッドがあります。1つはintを更新し、もう1つはそれを読み取ります。これは、読み取りと書き込みの順序が関係ない統計値です。

私の質問は、とにかくこのマルチバイト値へのアクセスを同期する必要がありますか?または、別の言い方をすれば、書き込みの一部が完了して中断され、その後読み取りが発生する可能性があります。

たとえば、0x00010000の増分値を取得する値= 0x0000FFFFについて考えてみます。

気になる値が0x0001FFFFのようになる時間はありますか?確かに、タイプが大きいほど、このようなことが起こる可能性が高くなります。

私は常にこれらのタイプのアクセスを同期してきましたが、コミュニティの考えに興味がありました。


5
本当に?私はコミュニティがどう思ったかは気にしません。私は事実が何であるかを気にします:)
sehe 2011

1
トピックに関する興味深い読み物:channel9.msdn.com/Shows/Going+Deep/…– ereOn 2013
9:01

回答:


47

最初は、ネイティブマシンサイズの読み取りと書き込みはアトミックであると考えるかもしれませんが、プロセッサ/コア間のキャッシュコヒーレンシを含む対処すべき問題がいくつかあります。WindowsではInterlocked *のようなアトミック操作を使用し、Linuxでは同等の操作を使用します。C ++ 0xには、これらを優れたクロスプラットフォームインターフェイスでラップするための「アトミック」テンプレートがあります。今のところ、プラットフォーム抽象化レイヤーを使用している場合は、これらの機能を提供する可能性があります。 ACEそうです。クラステンプレートACE_Atomic_Opを参照してください。


ACE_Atomic_Opのドキュメントが移動しました-dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/Atomic_Op.inl–
Byron

63

少年、なんて質問だ。その答えは次のとおりです。

はい、いいえ、うーん、まあ、それは依存します

それはすべて、システムのアーキテクチャに帰着します。IA32では、正しく整列されたアドレスはアトミック操作になります。アラインされていない書き込みはアトミックである可能性があり、使用しているキャッシングシステムによって異なります。メモリが単一のL1キャッシュライン内にある場合、それはアトミックです。そうでない場合はそうではありません。CPUとRAMの間のバスの幅は、アトミックな性質に影響を与える可能性があります。8086で正しく整列された16ビット書き込みはアトミックでしたが、8088では8ビットバスしかないため、8088での同じ書き込みはアトミックではありませんでした。 16ビットバス。

また、C / C ++を使用している場合は、共有値を揮発性としてマークすることを忘れないでください。そうしないと、オプティマイザーは、いずれかのスレッドで変数が更新されないと見なします。


23
volatileキーワードは、マルチスレッド・プログラムでは有用ではありませんstackoverflow.com/questions/2484980/...

5
@IngeHenriksen:私はそのリンクに納得していません。
スキズ2012

別のソースが、残念ながら非常に古い(それがのstd ::アトミック以前から):web.archive.org/web/20190219170904/https://software.intel.com/...
マックスBarraclough

11

4バイト値の読み取り/書き込みを行っていて、それがメモリ内でDWORDにアラインされていて、I32アーキテクチャで実行している場合、読み取りと書き込みはアトミックです。


2
インテルアーキテクチャソフトウェア開発者マニュアルのどこにこれが記載されていますか?
Daniel Trebbien 2011年

2
@DanielTrebbien:おそらくstackoverflow.com/questions/5002046/を

9

はい、アクセスを同期する必要があります。C ++ 0xでは、データの競合が発生し、未定義の動作になります。POSIXスレッドでは、それはすでに未定義の動作です。

実際には、データ型がネイティブワードサイズよりも大きい場合、悪い値が得られる可能性があります。また、最適化によって読み取りや書き込みが移動するため、別のスレッドが書き込まれた値を確認できない場合があります。


3

同期する必要がありますが、特定のアーキテクチャでは、同期するための効率的な方法があります。

実装をプラットフォーム固有の実装に条件付きで置き換えることができるように、サブルーチン(おそらくマクロの背後にマスクされている)を使用するのが最善です。

Linuxカーネルにはすでにこのコードの一部が含まれています。



2

誰もが2階で言ったことを反映するために、C ++ 0xより前の言語は、複数のスレッドからの共有メモリアクセスについて何も保証できません。保証はコンパイラー次第です。



0

私は多くの人、特にジェイソンに同意します。Windowsでは、InterlockedAddとその仲間を使用する可能性があります。


0

上記のキャッシュの問題は別として...

レジスタサイズが小さいプロセッサにコードを移植すると、アトミックではなくなります。

IMO、スレッドの問題は厄介すぎてリスクを冒すことができません。



0

この例を見てみましょう

int x;
x++;
x=x+5;

最初のステートメントは、単一のCPUサイクルを必要とする単一のINCアセンブリディレクティブに変換されるため、アトミックであると見なされます。ただし、2番目の割り当てにはいくつかの操作が必要なため、明らかにアトミック操作ではありません。

別の例、

x=5;

ここでも、コードを分解して、ここで正確に何が起こるかを確認する必要があります。


2
しかし、コンパイラはそれをに最適化することができx+=6ます。
TC。

0

tc、定数(6など)を使用した瞬間、命令は1マシンサイクルで完了しないと思います。x ++と比較してx + = 6の命令セットを確認してみてください


0

++ cはアトミックであると考える人もいますが、生成されるアセンブリに注目しています。たとえば、 'gcc -S'の場合:

movl    cpt.1586(%rip), %eax
addl    $1, %eax
movl    %eax, cpt.1586(%rip)

intをインクリメントするために、コンパイラは最初にそれをレジスタにロードし、それをメモリに格納します。これはアトミックではありません。


1
ティアリングがないため、1つのスレッドのみが変数に書き込んでいる場合、これは問題ではありません。
Ben Voigt 2012

0

絶対にNO!私たちの最高のC ++権限であるM.Boostからのその答え:
「通常の」変数に対する操作はアトミックであることが保証されていません。


2
そのリンクは、唯一の言うarithmetic「普通」の変数の読み取り更新-書き込みシーケンスで構成されて操作がないかどうか、アトミックではありませんreadwrite「普通」の変数の操作がアトミックかではありません。
d3Hunter 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.