Volatileについて調べてみた

スポンサーリンク

Volatileについてのまとめ

  • Volatileとは、対象となる変数のコンパイラー最適化を抑止する予約語
  • アトミック性、逐次性のいずれも保証されない。
  • もちろん排他制御されない
  • C言語はメモリモデルによっては可視性も保証されない?
  • volatile変数と非volatile変数との間では、コンパイラが2つの操作の実行順を入れ替える可能性がある
  • volatile変数が、その変数自体の以前の値にも他の変数にもまったく依存しないのであれば使えるケースもある。
    例:フラグ
    注:volatile変数同士であっても比較するケースでは使えない。

f:id:sato_susumu:20170909210617j:plain

一般的なVolatileの意味

揮発する、揮発性の、移り気な、気まぐれな、激しやすい、変わりやすい、不安定な
カナ:ボラタイル

Volatileが予約語かどうか

C:予約語
C#:予約語
Java:予約語
python:予約語ではない

Atomicな変数操作

  • Javaであればアトミック・クラスを使う
    例:AtomicInteger、AtomicBoolean、AtomicLong、AtomicIntegerArray
  • C++であれば、atomicクラステンプレート(std::atomic)を使う

Volatileとは(C言語)

アトミック性: 分割不可能な 1 単位の処理としてメモリ操作を実行できる 可視性: あるスレッドで実行した書き込み操作の結果が別のスレッドから見える 逐次性: あるスレッドによる一連のメモリ操作は、他のスレッドでも同じ順番で見えることが保証される

残念ながら、これらのどの特性についても、volatile 修飾子によって実現されるという保証はまったくない。 (中略) volatile キーワードの唯一の役割は、volatile として示されたメモリ領域で最適化を実行してはならない、ということをコンパイラに伝えることである。 https://www.jpcert.or.jp/sc-rules/c-pos03-c.html

volatileの注意(C言語)

volatile変数への読み書きは不可分(atomic)操作であるとは保証されない。 仮にレジスタサイズ2byte長のマシンを想定した場合、同環境では4byteサイズのvolatile変数アクセスはおそらく2回の2byteメモリアクセスに分割される。このとき異なるスレッドからvolatile変数へ読み/書きを同時に行うと、4byte領域のうち半分だけ更新された中間の値を読み込む可能性がある。つまり、プログラムの動作上は“どこにも存在しない値”を観測してしまうリスクがある。 2013-10-09 - yohhoyの日記

あくまで最適化の抑止(C言語)

コンパイラにとってソースコード上は冗長に見えるvolatile変数操作を、勝手に削除・移動しないという意味において、volatile変数は最適化抑制という効果をもつ。 ただし、該当のvolatile変数単体のみが対象、かつシングルスレッド実行を前提とすることに注意。 つまり、volatile変数(flag)と非volatile変数(data)との間では、この意味での最適化抑制効果はもたないため、コンパイラが2つの操作の実行順を入れ替える可能性がある。 また既に述べたとおり、異なるスレッドからの同一変数(flag)操作間の順序性には影響を及ぼさない。

volatile変数とマルチスレッドとの関係についての押し問答(後編) - yohhoyの日記

longとdoubleの代入や参照はアトミックでない(Java)

double 変数又は long 変数が volatile 宣言されていないとき,ロード,記憶,読取り,及び 書込み 動作の実行は,これらがそれぞれ32ビットの二つの変数であるかのように扱われる。これらの動作のいずれかが規則上要求されたときはいつでも,それぞれ32ビットの二回の動作として実行される。64ビットの double 変数又は long 変数を,二つの32ビット量として扱う方法は,実装依存とする。

JAVA言語規定 スレッドおよびロック

参考リンク

volatileで排他制御出来ると、いつから思ってた? atomicやsynchronized使うべし - Qiita
Javaの理論と実践: volatile を扱う