On the guarantee of atomicity in C
On x86 computers, instructions such as inc, addl are not atomic and in an SMP environment it is not safe to use them without the lock prefix. But in UP environment it is safe, as inc, addl and other simple instructions will not be interrupted.
My problem is, given a C level instruction like
x = x + 1;
Is there any guarantee that the C compiler will always use UP safe instructions such as
incl %eax
but aren't these unsafe instructions (for example, implementing a C instruction in multiple instructions that can be interrupted by the context switch) even in a UP environment?
source to share
There is absolutely no guarantee that it "x - x + 1"
will compile for instructions with interrupts on any platform, including x86. It is possible that it is safe for a particular compiler and a particular processor architecture, but it is not stipulated in the standards at all, and the standard is the only guarantee you get.
You cannot assume anything is safe based on what you think will compile. Even if a particular compiler / architecture claims to be there, relying on it is very bad since it reduces portability. Other compilers, architectures, or even later versions in the same compiler and architecture can break your code easily.
It is highly possible that it x = x + 1
can compile an arbitrary sequence such as:
load r0,[x] ; load memory into reg 0
incr r0 ; increment reg 0
stor [x],r0 ; store reg 0 back to memory
on a processor that has no instructions for expanding memory. Or it might be smart and compile it to:
lock ; disable task switching (interrupts)
load r0,[x] ; load memory into reg 0
incr r0 ; increment reg 0
stor [x],r0 ; store reg 0 back to memory
unlock ; enable task switching (interrupts)
where is lock
disabled, and unlock
- interrupts. But even then, it might not be safe on an architecture with more than one of these CPUs sharing memory ( lock
can only disable interrupts for one CPU), as you said.
The language itself (or libraries for it if it is not built into the language) will provide thread-safe constructs, and you should use them rather than rely on your understanding (or perhaps not understanding) of what machine code will be generated.
Things like Java synchronized
and pthread_mutex_lock()
(available for C under some OS) are what you want to learn.
source to share
Not.
You can use "volatile", which prevents the compiler from holding x in a temporary register, and for most purposes this will actually have the intended effect. But this is not guaranteed.
To be on the safe side, you should either use the inline asm, or if you need to be portable, encapsulate the increment with mutexes.
source to share
If you are using GLib, they have macros for atomic int and pointer operations.
http://library.gnome.org/devel/glib/stable/glib-Atomic-Operations.html
source to share
Recent versions of GCC have built-in __sync_xxx functions to do exactly what you want.
Instead of writing:
x + = 1;
write this:
__ sync_fetch_and_add (& x, 1);
And gcc will make sure it compiles to atomic opcode. This is now supported on the most important arches.
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html
This stems from Intel's recommendations for C on ia64, but has now found ways to use gcc for many other arcs. Therefore, it is even slightly portable.
source to share
A C compiler can implement a type statement x = x + 1
in multiple statements.
You can use the register keyword to hint that the compiler is using register instead of memory, but the compiler may ignore it.
I suggest using OS-specific locks such as the In-App Lock Function in Windows.
source to share
Worrying about x86 only is horribly unsporting coding. This is one of those seemingly small coding tasks that is a project in itself. Find an existing library project that solves this problem for a wide range of platforms and uses it. GLib seems to be one of what the Kaiser .se says.
source to share