Atomic
Atomic の実験をしてみました。下のコードの Reader スレッドでは表示されることはなさそうに見えますが、実際には何度も何度もいろいろな値が表示されます。
x86 ではボコボコ表示されます。
x64 では試した限りでは起きませんでした。でも起きないことは保障されてないハズ。半端なアライメントから値の領域がはじまったら2回のアクセスで読み書きするんじゃなかったかな。
using System; using System.Threading; namespace AtomicTest { class Program { private long value = 0; static void Main() { var p = new Program(); Action w = p.Writer; Action r = p.Reader; w.BeginInvoke( null, null ); r.BeginInvoke( null, null ); Console.WriteLine( long.MaxValue ); // 参考のため Console.WriteLine(); Console.ReadKey(); } void Writer() { while ( true ) { if ( this.value == 0 ) this.value = long.MaxValue; else if ( this.value == long.MaxValue ) this.value = 0; } } void Reader() { while ( true ) { if ( this.value != 0 && this.value != long.MaxValue ) Console.WriteLine( this.value ); Thread.Sleep( 100 ); } } } }
C# の仕様書より引用。
5.5 変数参照の分割不能性
bool、char、byte、sbyte、short、ushort、uint、int、float の各データ型および参照型の読み取りと書き込みは分割不可能です。また、上記の型を基になる型に持つ列挙型の読み取りと書き込みも分割不可能です。long、ulong、double、decimal などのその他のデータ型、およびユーザー定義型の読み取りと書き込みは、分割不可能であることが保証されていません。この目的で設計されたライブラリ関数を除いて、インクリメントやデクリメントの場合などでの分割不可能な読み取り/変更/書き込みは保証されていません。
long の読み書きはアトミックじゃない。
ついでに long に volatile もつけれない。
最後にお約束。BeginInvoke したら EndInvoke を呼ぶように。ごめんねいつもさぼって。