1

最も一般的なプラットフォーム(最も重要なのはx86です。一部のプラットフォームには、マルチスレッドに役立つ保証がほとんどない非常に難しいメモリモデルがあることを理解していますが、まれな反例は気にしません)、次のコードは安全ですか?

スレッド1:

someVariable = doStuff();
atomicSet(stuffDoneFlag, 1);

スレッド2:

while(!atomicRead(stuffDoneFlag)) {}  // Wait for stuffDoneFlag to be set.
doMoreStuff(someVariable);

アトミック操作の標準的で合理的な実装を想定すると、次のようになります。

  1. スレッド1の割り当ては、呼び出されるsomeVariable前に完了することが保証されていますか?atomicSet()
  2. スレッド2は、アトミックに読み取る場合、someVariable呼び出す前に割り当てを確認することが保証されていますか?doMoreStuff()stuffDoneFlag

編集:

  1. 私が使用しているアトミック操作の実装にはLOCK、役立つ場合は、各操作にx86命令が含まれています。
  2. stuffDoneFlagなんとかして適切にクリアされたと仮定します。どのように重要ではありません。
  3. これは非常に単純化された例です。問題のコンテキスト全体を理解して答える必要がないように、この方法で作成しました。私はそれが効率的ではないことを知っています。
4

5 に答える 5

2

実際のx86コードにスレッド1のatomicSetのストアの前にsomeVariableへのストアがあり、スレッド2のatomicReadのロード後にsomeVariableのロードがある場合は問題ありません。Intelのソフトウェア開発者マニュアル第3A巻では、セクション8.2でx86のメモリモデルを指定しています。ここでは、スレッド内のストア-ストアおよびロード-ロードの制約で十分です。

ただし、アトミック操作全体で使用している高級言語から生成された命令をコンパイラーが並べ替えることを妨げるものは何もない可能性があります。

于 2009-10-30T02:45:05.497 に答える
0

1)はい

2)はい

どちらも機能します。

于 2009-10-23T17:02:19.840 に答える
0

このコードはスレッドセーフに見えますが、非常に短い時間しかスピンしていない限り、スピンロック(whileループ)の効率に疑問があります。特定のシステムで、スレッド2がすべての処理時間を完全に占有しないという保証はありません。

スピンロックに頼るのではなく、実際の同期プリミティブ( boost :: condition_variableがここで必要なもののように見えます)を使用することをお勧めします。

于 2009-10-23T18:11:13.273 に答える
0

アトミック命令は、スレッド2が続行する前にスレッド1が変数の設定を完了するのをスレッド2が待機することを保証します。ただし、2つの重要な問題があります。

1)コンパイラが割り当てを最適化しないように、 「 volatilesomeVariable 」と宣言する必要があります。たとえば、レジ​​スタに格納したり、書き込みを延期したりします。

2)信号を待っている間、2番目のスレッドがブロックしています(スピンロックと呼ばれます)。あなたのプラットフォームはおそらくはるかに優れたロックとシグナリングのプリミティブとメカニズムを提供しますが、比較的簡単な改善は単にsleep()スレッド2のwhile()本体にあることです。

于 2009-10-23T18:20:01.553 に答える
0

dsimchaは次のように書いています。「stuffDoneFlagが何らかの方法で適切にクリアされていると仮定します。どのように重要ではありません。」 本当じゃない!

シナリオを見てみましょう:

  1. Thread2は、stuffDoneFlagがsomeVariableの読み取りを開始したかどうかをチェックします。
  2. Thread2がタスクスケジューラの読み取りを終了する前に、タスクを中断し、しばらくの間タスクを一時停止します。
  3. Thread1は再びsomeVariableにアクセスし、メモリの内容を変更します。
  4. タスクスケジューラが再びThread2をオンにすると、ジョブは続行されますが、someVariableのメモリコンテンツが変更されます。
于 2009-10-23T19:08:56.210 に答える