スレッド間でワード変数を共有するマルチスレッド アプリケーション (つまり、32 ビット システムで 32 ビット データ型) を使用している場合、そのワードの読み取りと書き込みをミューテックスで保護する必要がありますか?
2 に答える
キャッシュ、マルチコア、アウトオブオーダー実行などについて話すのではなく、ミューテックス (または割り込み操作などの他の相互排除技術) を使用する理由を説明するために、簡単な例を提供します。 )
変数を 1 ずつインクリメントするには (少なくとも最近私が扱っているほとんどのアーキテクチャでは)、値をメモリからレジスタに読み取り、レジスタ内の値を調整して、メモリに書き戻す必要があります。優先度の高い A と優先度の低い B の 2 つのスレッドがあるとします。次のシナリオを考えてみましょう。
- スレッド B は、メモリからレジスタに "x" を読み取ります (値は 5)。
- スレッド B はレジスタを値 6 にインクリメントします。
- スレッド A はスレッド B を横取りします。
- スレッド A は "x" をレジスタに読み取ります (メモリ内の値はまだ 5 ですよね?)。
- スレッド A はレジスタを値 6 にインクリメントします。
- スレッド A が値 6 をメモリに書き戻す
- スレッド A はスリープ状態になります。
- スレッド B が起動し、そのレジスタ値 6 をメモリに書き戻します。
両方のスレッドが値を増やしましたが、値は 1 つしか上がりませんでした。
これがエレベーターの階数、感知された心拍数、またはスペースシャトルのカウントダウン値 (OK、それは減分になります) である場合、問題が発生する可能性があります。
このインクリメント操作をアトミックに実行できるアーキテクチャ (通常は CISC) がいくつかあることに注意してください。
注: 場合によっては (ただしこれは行わないでください)、ライターが 1 つとリーダーが複数ある場合は、ミューテックスなしで済むことがあります。たとえば、ISR がティック カウントなどをインクリメントし、他のスレッド/タスクが頻繁にアクセスして読み取ります。
私が言いたいのは、共有データを保護しなくても済むと思っていても、常にそれを保護することは良い考えだということだと思います。「コマンドー」を実行したい場合は、自分が何をしているのかを本当に知っている必要があります。それでも、同じコードが明日新しいアーキテクチャに移植されたときに壊れる可能性があります。
一般に、はい、アクセスをミューテックスと同期する必要があります。メモリ位置への書き込みが「アトミック」であると思われる場合でも、CPU はそのメモリへの読み取りと書き込みの命令を並べ替え、望ましくない動作を引き起こす可能性があります。また、マルチコアまたはマルチ CPU システムでは、共有メモリの場所への書き込みは、同期しないと他のコア/CPU からすぐには認識されない場合があります。
詳細については、ウィキペディアのMemory Barrierの記事を参照してください。