volatile ついでに atomic
JavaとObjective-Cのvolatileがなんか違うような気がするので調べてみました。
変数に対する修飾子のひとつ。
単語の意味は、揮発しやすいとか変わりやすい。
こんな名前になったのは、「何もしていないのに勝手に値が変わるかもしれませんよ」ってのを示すためだそうです。
Javaのvolatile
複数のスレッドが参照する変数はただひとつ。みんなで同じ場所を覗いているので、他のスレッドが値を変更した瞬間に、他のスレッドでも変更した値を取得できる。
ただし、値を参照した直後に、もう一度値を参照しても、それが前の値と同じかどうかはわからない(不可分操作が保証されない)ので、使い方には充分注意しましょう。変わって欲しくない時はちゃんとsynchronizeとかロックで排他制御しましょうねってもの。
Objective-C(というかC)のvolatile
複数のスレッドが同じところを覗きます。まぁJavaと一緒です。 Cの場合はVMなJavaと違って、値をロードする時に同じ番地から読みますってのが保証されてます。volatileがついてる変数を触るコードはコンパイラの最適化が働かなかったりするので、パフォーマンスが落ちます。
似たような物としてメモリバリア(OSMemoryBarrier)ってのがあるらしく、CPUの最適化によってメモリアクセス順序が変わっちゃったりするのを抑制できるそうです(メモリの前に警備員を設置して、一定の手順でないとアクセスできないようにする)
どちらもあるスレッドが変更した結果が、他のスレッドにも即座に伝わるようにする機能。
不可分性を求めるのなら、やっぱりロックとか使って排他制御しなきゃ駄目ですよってことですね。
結局のところ、どちらも利用する場面に違いはなさそう。というかvolatile使う箇所ってあんまりないですよね…
そうそう、大事な事を書くのを忘れていました。一つのオブジェクトを複数のスレッドで操作する場合、volatileなんてなくても一緒じゃないの?って疑問が当然湧くとおもうのですが、高度に最適化が行われる現状ではこれは間違いです。最適化の結果、各々のスレッドが、元の変数の値を自分の参照し易いところにコピーして、それを操作し、適当なタイミングで元の場所に書き戻すなんて動作になる可能性もない訳ではありません。
ついでにatomic
プロパティの属性に atomic / nonatomicってのがありますが、あれはアクセサ(setter/getter)の中でロックが行われる代物なのだそうです。他のスレッドに対する一貫性は保てますが、真のatomicかといわれるとそうでもないので、atomicなんて使わなくて大丈夫だと、いろんなところで書かれているわけですね。 (本当に不可分操作したいときは、前後の処理も含めないと意味がないはずなので、アクセサ自分で書きますよねってことですね)