2008-09-16 23 views
2

私は競合状態と、同じ変数にアクセスする複数のスレッドの仕組みを理解しています。一方の更新は無視され、上書きされますが、各スレッドが同じ値(異なる値ではありません)これは問題を引き起こすことさえできますか?このコード:複数のスレッドが同じ変数に同じ値を書き込んでも構いませんか?

GlobalVar.property = 11;

(プロパティには11以外の値が割り当てられないと仮定します)、複数のスレッドが同時にそのスレッドを実行すると問題が発生しますか?

+0

あなたはどの言語を使用していますか? – GateKiller

答えて

1

私は結果が未定であると予想します。コンパイラ、コンパイラ、言語、OS、OSなどの違いがありますので、安全ではありません。

あなたはmutexロックを取得するために行を追加するだけですコードの1行または2行(ほとんどの言語で)、問題の可能性を排除します。これは2つの高価になる場合は、問題を解決する別の方法を見つける必要があります

2

それは実際にその文で行われた作業によって異なります。 Something Badが起きる場合もあります。たとえば、C++クラスが=演算子をオーバーロードしていて、そのステートメント内に何も重要なことがない場合などです。

私はPODタイプ(組み込みプリミティブタイプ)でこのようなことをしたコードを書いてしまいましたが、うまくいきましたが、間違いなく良い練習ではありません。確信が持てません。

なぜこの変数の周りにメモリをロックするだけでいいですか?実際に、何らかの形で "知っている"場合、これはコードのある時点で発生する可能性のある唯一の書き込み文です。共有変数に書き込むのではなく、値11を直接使用するのはなぜですか? (編集:私はそれがところで、コード内で直接magic number 11の代わりに定数名を使用することをお勧めだと思う。)

少なくとも一つのスレッドがこの文に達したときに把握するためにこれを使用している場合1から始まるセマフォを使用することができ、それをヒットする最初のスレッドによってデクリメントされます。

1

一般的に、システムがアトミック操作(1サイクルで実行することが保証されている操作)を提供しない限り、これは安全な処理ではありません。 "C"ステートメントはシンプルに見えますが、多くの基本的なアセンブリ操作が行われていることがあります。

お使いのOSによっては、あなたができるいくつかあります:

  • いくつかのOSにアクセス
  • を保護するために、相互排他セマフォ(ミューテックス)を取るが、あなたは一時的に保証され、プリエンプションを無効にすることができますスレッドはスワップアウトしません。
  • 一部のOSは、古いミューテックスよりもパフォーマンスの高いライターまたはリーダーセマフォを提供します。
-1

操作がアトミックの場合は、ですばらしいことがあります。しかし、私はそれを実際にはしません。オブジェクトのロックを取得して値を書き込む方がよいでしょう。

+0

アトミシティは、他のスレッドが自分の値を見過ごすことがないことを保証します。新しい価値の可視性は別の問題です。 –

7

あなたはその状態を読み返して何かをするときに問題が発生します。執筆は赤ん坊です - これが単一の単語である限り、ほとんどの環境では書込みはアトミックになることが保証されていますが、このフラグメントを含むコードのほうがスレッドセーフであるということではありません。第一に、おそらく、あなたのグローバル変数は、まずは別の値を含んでいたでしょう - そうでなければ、常に同じであることがわかっているのですが、なぜそれが変数ですか?第二に、おそらくあなたはこの値をもう一度読み返しますか?

問題は、おそらく、何らかの理由でこの共有状態のビットに書き込んでいるということです。これは落ちる場所です:あなたがロック構造を持たない場合、暗黙のメモリアクセスの順序はありません。

int x = 0, y = 0; 

//thread A does: 
x = 1; 
y = 2; 
if (y == 2) 
    print(x); 

//thread B does, at the same time: 
if (y == 2) 
    print(x); 

スレッドAは常に1を出力します、:あなたの例は、実際に中立Cに似た構文でtrivialish例ですので、ここでは、変数の使用が含まれていないので、ここで間違って何を指すのは難しいですスレッドBが0を出力することは完全に有効です。スレッドAの操作の順序は、スレッドAで実行されているコードから観察可能である必要があります。スレッドBは状態の任意の組み合わせを見ることができます。 xとyへの書き込みは、実際には順序どおりに行われるわけではありません。

これは、ほとんどの人がこのような並べ替えを期待しないシングルプロセッサシステムでも発生する可能性があります。つまり、コンパイラによって並べ替えが行われる可能性があります。 SMPでは、たとえコンパイラが何かを並べ替えないとしても、メモリの書き込みは、別々のプロセッサのキャッシュ間で並べ替えることができます。

それはあなたのためにそれを答えているようでない場合は、あなたの例の詳細を質問に含めてください。変数を使用しないと、そのような使用が安全かどうかを決定的に言うことは不可能です。

0

プロパティに11以外のものが割り当てられないと仮定すると、最初は譲渡の理由が表示されません。ちょうどそれを一定にしてください。

の値を変更するときには、のアサイメント行為には他の副作用があります(揮発性書き込みのようにJavaでメモリの可視性の副作用がある場合を除く)。また、複数のスレッド間で状態共有を変更した場合は、同時性の問題を同期化するか別の方法で処理する必要があります。

適切な同期がない値を複数のスレッド間で共有されている状態に割り当てると、他のスレッドがその変更をいつ表示するかは保証されません。また、可視性の保証がないということは、他のスレッドがとなる可能性がないことを意味します。はassigntを参照してください。

コンパイラ、JIT、CPUキャッシュ。彼らはすべてあなたのコードをできるだけ速く動かそうとしています。もしあなたがメモリの可視性について明示的な要求をしなければ、それを利用します。あなたのマシンにない場合、誰かがelses。

1

ここに私の質問があります。

ステータスフラグなどの変数に書き込むスレッドが2つ以上実行されています.1つ以上のスレッドが真であるかどうかを知りたいだけです。少なくともスレッド上でステータスが...例

bool flag = false 
threadContainer tc 
threadInputs inputs 

check(input) 
{ 
    ...do stuff to input 
    if(success) 
     flag = true 
} 

start multiple threads 
foreach(i in inputs) 
    t = startthread(check, i) 
    tc.add(t) // Keep track of all the threads started 

foreach(t in tc) 
    t.join() // Wait until each thread is done 

if(flag) 
    print "One of the threads were successful" 
else 
    print "None of the threads were successful" 

のために、私はあなたと仮定すると、上記のコードはOKだろうと信じていることを設定した場合、コードの別の部分(スレッドが完了した後)に、あなたはチェックして見てみたいですどのスレッドがステータスをtrueに設定しているかを知らずに済むので、そのフラグを読む前にすべてのマルチスレッドの処理が完了するのを待つことができます。私は間違っている可能性があります。

+0

私が一番よく知っているJava5メモリモデルでは、スレッドの開始と結合は合法的なハンドオフ方法であり、mfence()を適切に実行するので、そのコードはOKです。 –

関連する問題