2016-07-08 2 views
3

を変数を書き、読んで、私は自分自身にこの1つの質問をしてきましたかC++は、異なるスレッドから未定義の動作

スレッドの整数を増やし、別の整数の中の整数を読み込む最小限の例を考えてみましょう。

void thread1() 
{ 
    x++; 
} 

void thread2() 
{ 
    if (x == 5) 
    { 
     //doSomething 
    } 
} 

私はほかの操作はアトミックではないことを理解し、最初のスレッドが加算動作の途中である一方、それゆえ私は2番目のスレッドからの読み出しを行うことができますが、私はかなりよく分からないものがありますの。

xは、加算操作全体が完了してからこの新しい値が割り当てられるまで値を保持するか、xが中間状態であるため、未定義の動作が発生します。

最初の理論が適用される場合、書いている間にxから読み取ると、加算前の値が返され、それほど問題にはなりません。

二説が本当であるならば、誰かが(多分一例で?)加算演算のプロセスであり、なぜそれが未定義の動作がどうなるかをより詳細に説明できる

おかげ

+0

あなたは[this](http://preshing.com/20130618/atomic-vs-non-atomic-operations/)を読むべきです – WhiZTiM

+0

これはUBです。スレッド2は 'x'の値が変わるのを保証する保証はありません。さらに悪いことに、コンパイラは、 'x'が決して変更されず、' if'テストを取り除く理由を考えるかもしれません。 'std :: atomic <*>'について読んでください。 –

+0

ちょうど好奇心のために:どのようにコンパイラが別のスレッドで実行され、ifを削除することを知っていますか? – Aik

答えて

-3

X( 32ビット変数)は32ビットCPUで常に定義されますが、正確にはそうではありません。あなたは、xが++で定義された開始範囲から終了範囲までの任意の値であることを知っています。ケースを次のように

:xが0に初期化されていて、それは私がアトミックとしてメモリに整数の割り当てを検討することができることを意味し、0〜5

の範囲で、このXを見ることができますスレッド2スレッド1 5回を呼び出します。

両方のスレッドのxが同期していない理由はいくつかあります。スレッド1上のxはスレッド2上で5ですが、同時に同じ時間に0にすることができます。 理由の1つは、コアごとに異なるcpuキャッシュです。キャッシュ間で値を同期させるには、メモリバリアを使用する必要があります。たとえば、あなたのために偉大な仕事をするstd::atomicを使用することができます

+1

カウントの心配の数に間違っています。 'x'は必ずしも32ビットではなく、その幅はあいまいな「CPU幅」に依存しません。 'x'は範囲を持っていますが、' ++ 'で定義されていません。型は 'int'で、' atomic 'ではないので、' x'型の原子を考えることはできません。後者のタイプの理由があります。そして、同期なしでは、他のスレッドは、0から5だけでなく、6、-1および紫の値を見ることができます。 (はい!非同期アクセスには何の制限もありません) – MSalters

0

コメントは基本的な権利をすでに持っています。

コンパイラは、単一の関数をコンパイルするときに、変数の変更方法を検討することがあります。関数が直接的または間接的に特定の変数を変更できない場合、にスレッド同期がない限り、その変数には何も変更されていないとみなされます()。その場合、コンパイラは別のスレッドがこれらの変数を変更する可能性に対処する必要があります。

コンパイラの前提条件に違反した場合(つまりバグがある場合)、文字通り何かが起こる可能性があります。オプティマイザを厳しく制限するため、これは制約されません。 xにはいくつかの固有のアドレスがありますが、オプティマイザは変数を移動し、複数の変数が単一のアドレスを共有することを前提としています。このような最適化は、単一スレッドの仮定、つまりあなたの例が違反していることに基づいて非常に正当化される可能性があります。 2番目のスレッドはxを見ていると思うかもしれませんが、yになっている可能性もあります。

関連する問題