2017-01-07 10 views
2

私はmutexを研究しています。ここでスレッド同期を使用することはできますか?

この例は、同期なしで動作するように見えます。

#include <cstdint> 
#include <thread> 

#include <iostream> 

constexpr size_t COUNT = 10000000; 

int g_x = 0; 

void p1(){ 
    for(size_t i = 0; i < COUNT; ++i){ 
     ++g_x; 
    } 
} 

void p2(){ 
    int a = 0; 

    for(size_t i = 0; i < COUNT; ++i){ 
     if (a > g_x){ 
      std::cout << "Problem detected" << '\n'; 
     } 

     a = g_x; 
    } 
} 

int main(){ 
    std::thread t1{ p1 }; 
    std::thread t2{ p2 }; 

    t1.join(); 
    t2.join(); 

    std::cout << g_x << '\n'; 
} 

私の仮定は以下のとおりである。g_xの値

スレッド1つの変化を、それが値を変更するだけのスレッドなので、理論的にはこれがOKであることを仮定します。

スレッド2は、g_xの値を読み取ります。読み込みは、x86とARMではアトミックであると仮定します。だからそこにも問題はないはずです。私はいくつかの読み取りスレッドの例があり、それもOKを動作します。

つまり、書き込みは共有されず、読み取りはアトミックです。

仮定は正しいですか?

+0

't1'は' a> g_x1'( 't1'の' g_x1'の 'g_x1'の値)になります。 'a == g_x0' - ある時点で' t0'( 't0 <= t1')' a'が 'g_x'から割り当てられます。 't0 <= t1'と' g_x0> g_x1'となります。別の側からは 'g_x'だけインクリメントします - したがって' t0 <= t1' => 'g_x0 <= g_x1' - 矛盾です。その結果、 'a> g_x'は決して起こらないと言うことができます。ここで何を試してみるのですか?この種のコードでは(あるスレッドがint変数をインクリメントするとき)、別のスレッドはランダムなタイミングでこのintを読み込みます。同期は必要ありません。しかし何? – RbMm

+0

'if(a> g_x){'これは 'g_x'だけが増加することを示す一種のテストです。別のテストをお勧めしますか? – Nick

+0

何のテスト?あなたは何を証明しようとしますか?しかし、もし私が間違っていないなら、あなたの "テスト"(a <= g_x)で、常に設計されています。ここで同期に関係していない – RbMm

答えて

4

確かにデータ競争があります:g_xstd::atomicではありません。 1つのスレッドによって書き込まれ、別のスレッドによって読み込まれます。結果は未定義です。

CPUメモリモデルは、取引の一部に過ぎないことに注意してください。共有変数を適切に宣言しないと、コンパイラはあらゆる種類の最適化(レジスタ、並べ替えなどを使用)を行う可能性があります。

ミューテックスについては、ここでは必要ありません。 g_xをアトミックとして宣言すると、UBが削除され、スレッド間の適切な通信が保証されます。 Btw、アトミックを使用している場合でもp2のforはおそらく最適化されていますが、これは実際のものではなくコードの縮小であると想定しています。

+0

私は同様に読書のためにミューテックスが必要ですか? (私は原子が最善の選択であることを知っています) – Nick

+1

あなたは原子やフェンスを使用していない場合は、はい。しかし、それはあなたの場合には過剰です。 Atomicsは、アーキテクチャのメモリモデルが必要以上に緩和されている場合にのみ、メモリ操作にオーバーヘッドを追加します。そうでない場合、アトミックの唯一のコストは最適化を避けているため、あなたは必然的に避けたいものです。 – eran

+0

私はそれをアトミックに変更し、 'g_x.is_lock_free()'は真です。これがどのように状況に関連しているか。 – Nick

関連する問題