volatile
読み:ヴォラタイル
外語:volatile

 C/C++/C#/Java予約語の一つ。
 変数を修飾する。コンパイラーが変数の値に関して、コードの見かけ上値が変化しないなどの仮定を行なうことを抑止する。
目次

概要
 変数を修飾し、最適化を抑制する。
 言語により機能は様々だが、メモリーマップドI/Oであったり、マルチスレッド環境で複数のスレッドから変更される可能性があるフィールドであることを明示するのに用いる。
 volatileで宣言されているフィールドは、シングルスレッドでのアクセスを前提としたコンパイラーの最適化の対象から外される。

特徴

由来
 当初のCにはなく、ANSI Cから追加された。
 この当時はまだシングルスレッドが前提ではあったが、例えばメモリーマップドI/O空間のデバイスのレジスター値など、コードの外部で変更される可能性のある値へのアクセスが不用意に最適化されてしまう問題を回避することを目的としていた。
 もしこれがないと、ある同じアドレスのポートに連続して値を書く場合、それらが無駄な処理と判断され、最後の書き込みのみを残してそれ以外が削除されてしまう可能性がある。
 そういった、コンパイラーの最適化機能を抑止するために定義されたものが、このvolatileである。

マルチスレッド
 volatileによる最適化抑制は、のちのマルチスレッド環境用のプログラミングでも活用された。
 現在のプロセッサーは、アウトオブオーダー実行により、命令が並べ替えて実行されることがある。メモリーマップドI/Oはもちろんだが、複数のスレッドからアクセスする変数が複数あり、その更新のタイミングが重要な場合、命令の実行順序が変わることで致命的な動作を招く可能性がある。
 C#では、volatileがメモリーバリアを生成することになっている。volatileを使うことで、CPUのメモリーバリア機能などを用い、実行順序の保証がなされる。なお、他の言語では必ずしもそうではない。

従来のC++
 従来のC++はコンパイラー依存。
Visual C++
gcc

C++11とJava
 C++11はstd::atomic、JavaはAtomic*型がメモリーバリアとしての機能を持っている。

用例
 例えば8ビットCPUであることを仮定し、アドレス0xffffにI/Oポートがあるとすると、
 #define IOPORT (*(volatile unsigned char *)0xffff)
 のようにすると、IOPORTでポートにアクセス可能となる。
 ここに0xaaと0x55を交互に書いたあと参照するハードウェアであったとすると、次のような記述が可能になる。
 IOPORT = 0xaa;
 IOPORT = 0x55;
 IOPORT = 0xaa;
 IOPORT = 0x55;
 printf("%02hhx", IOPORT);
 もしvolatileの指定がない場合、コンパイラーの最適化により、最後の0x55の書き込みのみが有効になる恐れがある。

再検索