tags:

views:

515

answers:

4

In Java, updating double and long variable may not be atomic, as double/long are being treated as two separate 32 bits variables.

http://java.sun.com/docs/books/jls/second_edition/html/memory.doc.html#28733

In C++, if I am using 32 bit Intel Processor + Microsoft Visual C++ compiler, is updating double (8 byte) operation atomic?

I cannot find much specification mention on this behavior.

When I say "atomic variable", here is what I mean :

Thread A trying to write 1 to variable x. Thread B trying to write 2 to variable x.

We shall get value 1 or 2 out from variable x, but not an undefined value.

A: 

I wouldn't think in any architecture, thread/context switching would interrupt updating a register halfway so that you are left with for example 18bits updated of the 32bits it was going to update. Same for updating a memory location ( provided that it's a basic access unit, 8,16,32,64 bits etc).

Indeera
The problem is not context switching, it is multicore and multicpu.
AProgrammer
Even in multicore/multi cpu architecture physical memory access has to be serialised by the memory controller. It's electrically impossible to let multiple devices access the same circuitry at the same time duration. Memory controller accesses memory in blocks, and in whole units of data bus width, therefore it's not possible to have partial update of a memory location.
Indeera
So what about if the double lies across the boundary of two cache lines? I doubt that MSVC++ will do that, because everything will be aligned to its size in powers of 2. But if you're generalising, it's not a requirement of the C++ standard (and in at least one of the ARM ABIs, longs and doubles only have to be 4-aligned, not 8-aligned).
Steve Jessop
+5  A: 

This is hardware specific and depends an the architecture. For x86 and x86_64 8 byte writes or reads are guaranteed to be atomic, if they are aligned. Quoting from the Intel Architecture Memory Ordering White Paper:

Intel 64 memory ordering guarantees that for each of the following memory-access instructions, the constituent memory operation appears to execute as a single memory access regardless of memory type:

  1. Instructions that read or write a single byte.

  2. Instructions that read or write a word (2 bytes) whose address is aligned on a 2 byte boundary.

  3. Instructions that read or write a doubleword (4 bytes) whose address is aligned on a 4 byte boundary.

  4. Instructions that read or write a quadword (8 bytes) whose address is aligned on an 8 byte boundary.

All locked instructions (the implicitly locked xchg instruction and other read-modify-write instructions with a lock prefix) are an indivisible and uninterruptible sequence of load(s) followed by store(s) regardless of memory type and alignment.

drhirsch
It also depends on the compiler, which is not required to ensure that doubles are 8-aligned in the first place, or to use a single quadword op to read or write them. Although you'd think it probably will, and also I expect that visual c++ documents whether it does or not.
Steve Jessop
Yes, this is specified in the compilers ABI. For non-auto variables doubles are always aligned, except if explicitly specified non aligned. For variables on the stack in a 32 bit system they may become unaligned if stack is somehow getting unaligned, for example, a funcitions is called from a extern, non-C program. But you don't want to return objects from stack in a function anyway...
drhirsch
You don't return automatics, but you might pass a pointer to them into a function you call. But I guess what you've said is sufficient for the questioner - as long as he controls how they were defined, he can ensure that access to his doubles is atomic.
Steve Jessop
A: 

So has this question been answered? I ran a simple test program changing a double:

#include <stdio.h>

int main(int argc, char** argv)
{
    double i = 3.14159265358979323;
    i += 84626.433;
}

I compiled it without optimizations (gcc -O0), and all assignment operations are performed with single assembler instructions such as fldl .LC0 and faddp %st, %st(1). (i += 84626.433 is of course done two operations, faddp and fstpl).

Can a thread really get interrupted inside a single instruction such as faddp?

"Can a thread really get interrupted inside a single instruction such as faddp?". No, thread cannot be "interrupted" inside a single instruction, by two CPUs can be performing their instructions at the same time, and one CPU can see only the part of the result of the second CPU if the instruction is not performed in a single bus transaction.
Suma