You can try running it through CHESS to make sure that this can force an interlace that breaks the test.
If you look at the x86 graphics (visible from the debugger), you can also see if jitter generates instructions that preserve atomicity.
EDIT: I went ahead and started disassembling (forcing the x86 target). Matching lines:
double dCopy = _d; 00000039 fld qword ptr ds:[00511650h] 0000003f fstp qword ptr [ebp-40h] _d = rand.Next(2) == 0 ? 0D : double.MaxValue; 00000054 mov ecx,dword ptr [ebp-3Ch] 00000057 mov edx,2 0000005c mov eax,dword ptr [ecx] 0000005e mov eax,dword ptr [eax+28h] 00000061 call dword ptr [eax+1Ch] 00000064 mov dword ptr [ebp-48h],eax 00000067 cmp dword ptr [ebp-48h],0 0000006b je 00000079 0000006d nop 0000006e fld qword ptr ds:[002423D8h] 00000074 fstp qword ptr [ebp-50h] 00000077 jmp 0000007E 00000079 fldz 0000007b fstp qword ptr [ebp-50h] 0000007e fld qword ptr [ebp-50h] 00000081 fstp qword ptr ds:[00159E78h]
It uses one fstp qword ptr to perform a write operation in both cases. I assume that the Intel processor guarantees the atomicity of this operation, although I have not found any documentation to support it. Any x86 gurus who can confirm this?
UPDATE:
This is not as expected if you are using Int64, which uses 32-bit registers on an x86 processor, rather than special FPU registers. You can see it below:
Int64 dCopy = _d; 00000042 mov eax,dword ptr ds:[001A9E78h] 00000047 mov edx,dword ptr ds:[001A9E7Ch] 0000004d mov dword ptr [ebp-40h],eax 00000050 mov dword ptr [ebp-3Ch],edx
UPDATE:
I was curious if this didn't work, if I forcibly align non-8-byte double-field alignment in memory, so I compiled this code:
[StructLayout(LayoutKind.Explicit)] private struct Test { [FieldOffset(0)] public double _d1; [FieldOffset(4)] public double _d2; } private static Test _test; [STAThread] static void Main() { new Thread(KeepMutating).Start(); KeepReading(); } private static void KeepReading() { while (true) { double dummy = _test._d1; double dCopy = _test._d2;
This will not work, and the generated x86 instructions are essentially the same as before:
double dummy = _test._d1; 0000003e mov eax,dword ptr ds:[03A75B20h] 00000043 fld qword ptr [eax+4] 00000046 fstp qword ptr [ebp-40h] double dCopy = _test._d2; 00000049 mov eax,dword ptr ds:[03A75B20h] 0000004e fld qword ptr [eax+8] 00000051 fstp qword ptr [ebp-48h]
I experimented with replacing _d1 and _d2 for use with dCopy / set, and also tried FieldOffset from 2. Everyone generated the same basic instructions (with different offsets above), and all this didn't work after a few seconds (probably billions of attempts) , I am cautiously sure, considering these results, at least Intel x86 processors provide atomic double-boot / storage operations regardless of alignment.