24

MSDNによると:

volatile キーワードは、同時に実行されている複数のスレッドによってフィールドが変更される可能性があることを示します。volatile と宣言されたフィールドは、シングル スレッドによるアクセスを想定したコンパイラの最適化の対象ではありません。これにより、最新の値が常にフィールドに存在することが保証されます。

最後の文に注目してください:

これにより、最新の値が常にフィールドに存在することが保証されます。

しかし、このキーワードには問題があります。

命令の順序を変更できることを読みました:

First instruction       Second instruction         Can they be swapped?
Read                         Read                         No
Read                         Write                        No
Write                       Write                         No 
Write                       Read                          Yes! <----

これは、John が volatile フィールドに値を設定し、後でPaul がそのフィールドを読み取りたいと考え、Paul が古い値を取得していることを意味します。

ここで何が起こっているのですか?それが本職じゃないの?

他の解決策があることは知っていますが、私の質問は volatile キーワードに関するものです。

私 (プログラマーとして) は、このキーワードの使用を避ける必要がありますか?

4

3 に答える 3

18

あなたは正しいです。ジョセフ・アルバハリのスレッドブック/記事で詳しく説明されています。

MSDN のドキュメントには、volatile キーワードを使用すると、常に最新の値がフィールドに存在することが保証されると記載されています。これは正しくありません。これまで見てきたように、書き込みに続いて読み取りが行われる可能性があるためです。

http://www.albahari.com/threading/part4.aspx#_The_volatile_keyword

私 (プログラマーとして) は、このような奇妙な動作のために、このキーワードの使用を防ぐ必要がありますか?

この奇妙な動作を知った後にのみ使用する必要があります。マルチスレッド環境で常に最新の値を取得するための Magic キーワードとして使用しないでください。

IMO、可能性のあるバグを見つけるのが難しいため、volatile キーワードの使用は避ける必要があります。

于 2012-05-17T07:41:14.830 に答える
7

MSDN のドキュメントは間違っています。それは確かにそうではありませんvolatile。C# の仕様は正確に何をするかvolatileを示しており、「新鮮な読み取り」または「コミットされた書き込み」を取得することはそれらの 1 つではありません。仕様は正しいです。volatile読み取りでの取得フェンスと書き込みでの解放フェンスのみを保証します。これらは以下のように定義されています。

  • acquire-fence: 他の読み取りと書き込みがフェンスのに移動できないメモリ バリア。
  • release-fence: 他の読み取りと書き込みがフェンスのに移動できないメモリ バリア。

矢印表記を使って表を説明しようと思います。↓ 矢印は揮発性読み取りを示し、↑ 矢印は揮発性書き込みを示します。命令は矢印を通って移動できません。矢じりはすべてを押しのけるものと考えてください。

次の分析では、変数を使用します。xy。また、それらが としてマークされていると仮定しvolatileます。

ケース #1

の読み取りの後に矢印を配置すると、読み取りが上に移動しxないことに注意してください。また、この場合、 のボラティリティは無関係であるyことに注意してください。y

var localx = x;
↓
var localy = y;
↓

ケース#2

の読み取り後の矢印の配置がx、書き込み先の移動を妨げていることに注意しyてください。また、この場合、両方ではなくどちらか一方のボラティリティを省略できることにxも注意してください。y

var localx = x;
↓
↑
y = 1;

ケース #3

write to の前に矢印を配置すると、write toが下に移動しyないことに注意してください。xこの場合、 のボラティリティxは無関係であることに注意してください。

↑
x = 1;
↑
y = 2;

ケース#4

xへの書き込みと の読み取りの間に障壁がないことに注意してくださいy。このため、 への書き込みxが浮動するか、 の読み取りyが浮動する可能性があります。どちらの動きも有効です。これが、書き込みと読み取りの場合の命令を交換できる理由です。

↑
x = 1;
var localy = y;
↓

注目すべき言及

また、次の点に注意することも重要です。

  • x86 ハードウェアには、書き込みに関する揮発性セマンティクスがあります。
  • Microsoft の CLI の実装 (および疑わしい Mono の実装も) には、書き込みに関する不安定なセマンティクスがあります。
  • ECMA 仕様には、書き込みに関する揮発性セマンティクスがありません。
于 2012-05-17T14:05:58.040 に答える
4

Joseph Albahari が提起したもう 1 つのポイントは、プロセス アーキテクチャが揮発性に悪影響を与える可能性があることです。つまり、AMD は特に値の交換を引き起こす可能性があります。

アプリケーションが本番環境でどのシステム タイプで実行されるかはおそらくわからないため、volatile キーワードは常に避けるのが最善です。

また、トピックから少し外れますが、マルチプロセッサ システムの負荷が高い場合は、ReaderWriterLock クラスを常に避ける必要があります。これにより、複数の書き込みロックが同時に取得される可能性があります。ここを参照してください。これにより、アプリケーションがハングし、根本原因を特定することが非常に困難になります。

于 2012-05-17T08:08:48.793 に答える