仕事で volatile 宣言が話題になった。
動きがおかしくなるので何も考えずに付けてきたが、
はてさて、詳しい意味はどうなんだろう?
--- --- 以下、引用 --- ---
棒MLでvolatileが話題に上がっていました。実は今までvolatileが何のためにあって、何に使うのが分かっていませんでした。ぶっちゃけ存在すら記憶のかなたに忘れていました。殆どのアプリケーションはvolatileの存在を忘れていても、運良く動いてしまいますから・・・。でも運に頼っていたなんて、プロ失格です。orz
以下のようなコードを記述した場合、volatileで宣言していないとThreadBで値を変更してもThreadAはループから脱出できない場合があります。コンパイラがコードを最適化した結果、メモリ上の値を取得するのではなく、CPUレジスタに退避されている値を参照する可能性があるためです。あるいは逆にThreadBで行っている代入はCPUレジスタにだけ反映され、メモリには書き込まれないかもしれません。このような場合2つのスレッドは同じ変数を参照しているにもかかわらず、同じ値を参照していないと言う状態が発生します。
voltileで宣言した場合、必ず変数への参照は最適化されずに、必ずメモリの値を取得するようになります。それによって上記のような現象を避けることが出来ます。本来、複数のThreadから参照する可能性のある変数は全てvolatile宣言する必要があります。
volatile int abort = 0;
UINT ThreadA(LPVOID)
{
while(!abort)
{
...
}
}
UINT ThreadB(LPVOID)
{
....
abort = 1;
}
もちろん代償もあります。volatile宣言を行った場合、コードは最適化されないので、実行速度の低下をもたらします。したがって複数のThreadから参照する可能性のある変数は、必要最小限にしなくてはなりません。
このvolatile宣言、あらためて確認していたらC#にもあるのですね。C#の場合にはC++と同じように変数宣言時にvolatileを指定します。また言語に限らずShared(public static)に宣言された変数はvolatile宣言した変数と同じように扱うそうです。
C++ならコンパイル時に幸運に恵まれればvolatileを忘れてもアプリケーションは問題なく動きました。一度コンパイルされたコードが実行中に最適化され、メモリからデータを取得しなくなる可能性はありませんでしたから。でも.Netではそうは行きません。実行時最適化機能によってコードが最適化される可能性があるため、volatileを忘れると何時おかしな動作をしだすか予想できません。volatile宣言を忘れないように気をつけましょう。:-)
http://blogs.msmvp.jp/mikahosi/archive/2005/02/03/366.aspx