3

私は常に、複数のスレッドがアクセスする変数の周りにロックをかけるように言われてきました。これは、書き戻す前に、作業している値が変更されないことを確認したいからだといつも思っていました。

mutex.lock()
int a = sharedVar
a = someComplexOperation(a)
sharedVar = a
mutex.unlock()

そして、それはあなたがそれをロックすることは理にかなっています。しかし、他のケースでは、ミューテックスを使用しないことで逃げられない理由がわかりません。

スレッドA:

sharedVar = someFunction()

スレッドB:

localVar = sharedVar

この場合、何がうまくいかない可能性がありますか?特に、スレッドBがスレッドAによって割り当てられた特定の値を読み取ることを気にしない場合。

4

4 に答える 4

5

sharedVarの種類、使用している言語、フレームワーク、およびプラットフォームに大きく依存します。多くの場合、単一の値を に代入するのsharedVarに複数の命令が必要になる可能性があります。その場合、値の「半分セット」のコピーを読み取ることができます。

そうではなく、割り当てがアトミックな場合でも、メモリ バリアがないと最新の値が表示されない場合があります。

于 2012-12-13T21:08:53.367 に答える
4

MSDN マガジンには、マルチスレッド コードで発生する可能性のあるさまざまな問題についての適切な説明があります。

  • 忘れられた同期
  • 粒度が正しくない
  • 読み書きティアリング
  • ロックフリーの並べ替え
  • コンボイをロック
  • ツーステップダンス
  • 優先順位の逆転

あなたの質問のコードは、読み取り/書き込みティアリングに対して特に脆弱です。ただし、ロックもメモリ バリアもないコードは、ロックフリー リオーダリング (スレッド A が格納したことのない値をスレッド B が読み取る投機的書き込みが含まれる場合があります) の対象となり、その副作用が 2 番目のスレッドに表示されます。ソース コードでの表示順序とは異なります。

これらの問題を回避するいくつかの既知の設計パターンについて説明します。

  • 不変性
  • 純度
  • 隔離

記事はこちらから入手できます

于 2012-12-13T21:17:51.483 に答える
2

主な問題は、代入演算子 (C++ では operator=) が常にアトミックであることが保証されていないことです (プリミティブな組み込み型の場合でも)。簡単に言えば、割り当てが完了するまでに 1 クロック サイクル以上かかる可能性があることを意味します。その途中でスレッドが中断された場合、変数の現在の値が壊れている可能性があります。

あなたの例から構築させてください:

次のように定義されたsharedVarオブジェクトがあるとしましょう:operator=

object& operator=(const object& other) {
    ready = false;
    doStuff(other);
    if (other.value == true) {
        value = true;
        doOtherStuff();
    } else {
        value = false;
    }
    ready = true;
    return *this;
}

あなたの例のスレッド A がこの関数の途中で中断された場合、スレッド B が実行を開始すると、ready はまだ false になります。これは、スレッド B がオブジェクトをローカル変数にコピーしようとしたときに、オブジェクトが部分的にしかコピーされていないか、中間の無効な状態にあることを意味する可能性があります。

これの特に厄介な例として、削除されたノードが削除され、NULL に設定される前に中断されたデータ構造を考えてみてください。

(ロックを必要としない構造 (別名、アトミック) に関する詳細については、それについてもう少し詳しく説明する別の質問をご覧ください。)

于 2012-12-13T21:16:25.723 に答える
0

スレッドはスレッドスケジューラによって一時停止および再開される可能性があるため、これらの命令が実行される順序を確認できないため、これはうまくいかない可能性があります。次の順序でもかまいません。

スレッド B:

localVar = sharedVar

スレッド A:

sharedVar = someFunction()

その場合localvar、null または 0 (または安全でない言語では完全に予期しない値) になり、おそらく意図したものではありません。

ちなみに、実際にはミューテックスはこの特定の問題を修正しません。あなたが提供する例は、並列化には適していません。

于 2012-12-13T21:11:43.330 に答える