2008-09-10 12 views
69

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

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

たとえば、0x00010000という値が増えた値= 0x0000FFFFと考えてください。

私は心配すべき0x0001FFFFのような値が現れますか?確かにタイプが大きくなればなるほど、これが起こる可能性が高くなります。

私はいつもこれらのタイプのアクセスを同期しましたが、コミュニティが何を考えているのか不思議でした。

+4

?私はコミュニティが何を考えているか気にしません。私は事実が何であるか心配だろう:) – sehe

+1

興味深いトピックの読んで:http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1- of-2 – ereOn

+0

特に '='の場合:http://stackoverflow.com/questions/8290768/is-assignment-operator-atomic –

答えて

39

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

+0

ACE_Atomic_Opの文書が移動しました。http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/Atomic_Op.inlにあります。 – Byron

+0

私はリンクを更新しました –

0

いいえ、そうではありません(または、少なくともあなたはそれらを想定することはできません)。これを言えば、これをアトミックに行うにはいくつかのトリックがありますが、通常はポータブルではありません(Compare-and-swap参照)。

8

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

実際には、データ型がネイティブワードサイズより大きい場合、値が不正になる可能性があります。また、別のスレッドは、読取りおよび/または書込みを移動させる最適化のために書かれた値を決して見ることができない。

3

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

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

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

9

4バイトの値を読み書きしていて、それがメモリにDWORDで整列されていて、I32アーキテクチャで実行している場合、読み書きは不可分です。

+2

ここでは、Intelアーキテクチャのソフトウェア開発者マニュアルにこれが記載されていますか? –

+1

@DanielTrebbien:おそらくhttp:// stackoverflowを参照してください。com/questions/5002046/c-myth-or-realityのアトミック性 – sehe

57

男の子、どういう質問ですか?答えは次のとおりです。

うーん、いや、はい、まあ、それはそれはすべて、システムのアーキテクチャにまで来て

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

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

+14

volatileキーワードはマルチスレッドプログラムでは役に立たないhttp://stackoverflow.com/questions/2484980/why-is-volatile-not-considered-useful -in-multithreaded-c-or-c-programming –

+3

@IngeHenriksen:私はそのリンクでは納得できません。 – Skizz

0

多くの、特にJasonに同意します。ウィンドウでは、InterlockedAddとその友人が使用される可能性があります。

1

誰もが2階で言ったことをエコーするために、C++ 0xより前の言語は、複数のスレッドからの共有メモリアクセスについて何も保証できません。すべての保証はコンパイラーに任されます。上記のキャッシュの問題から

0

Asside ...

それはもうアトミックではありませんあなたはポート小さいレジスタサイズとプロセッサへのコードをした場合。

IMO、スレッドの問題は、それを危険にさらすにはあまりにも厄介です。

3

Windowsの場合、インターロックされた*** Exchange ***追加はアトミックであることが保証されています。

-1

唯一の移植可能な方法は、コンパイラ用にsignal.hヘッダーに定義されているsig_atomic_t型を使用することです。ほとんどのCおよびC++実装では、それはintです。あなたの変数を "volatile sig_atomic_t"と宣言してください。

+0

volatileは何もしませんあなたはそれがそうだと思うhttp://stackoverflow.com/questions/2484980/why-is-volatile-not-considered-useful-in-multithreaded-c-or-c-programming –

0

は、最初の文は、それが単一のCPUサイクルを要する単一INCアセンブリ命令に変換するのでアトミックであると仮定される。この例

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

を取ることができます。しかし、2番目の割り当てはいくつかの操作を必要とするため、明らかにアトミックな操作ではありません。

別例えば、

x=5; 

は再び、あなたは正確にここに何が起こるか見るために、コードを逆アセンブルする必要があります。

+0

しかし、コンパイラは 'x + =' 6 '。 –

0

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

0

++ cはアトミックですが、生成されたアセンブリを見ている人もいます。と例えば「GCC -S」:

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

がintをインクリメントするには、コンパイラが最初のレジスタにロードし、バックメモリに格納します。これは原子ではない。

+1

ティアリングがないので、変数に書き込むスレッドが1つだけの場合でも問題ありません。 –

1

確定的にNO!私たちの最高のC++機関から答える 、M.ブースト:本当に
Operations on "ordinary" variables are not guaranteed to be atomic.

+0

このリンクは、 '普通の'変数のread-update-writeシーケンスからなる 'arithmetic'演算のみがアトミックではなく、 '普通の'変数の' read'や 'write'演算がアトミックかどうかではありません。 – D3Hunter

関連する問題