views:

3804

answers:

5

In a program I work on, I have a lot of code as follows:

pthread_mutex_lock( &frame->mutex );
frame->variable = variable;
pthread_mutex_unlock( &frame->mutex );

This is clearly a waste of CPU cycles if the middle instruction can just be replaced with an atomic store. I know that gcc is quite capable of this, but I haven't been able to find much documentation on such simple thread-safe atomic operations. How would I replace this set of code with an atomic operation?

(I know that simple stores should theoretically be atomic, but I don't want to have to hope that the optimizer isn't screwing up their atomic-ness at some point in the process.)

Clarification: I do not need them to be strictly atomic; these variables are solely used for thread synchronization. That is, Thread B reads the value, checks if its correct, and if its not correct, it sleeps. So even if Thread A updates the value and Thread B doesn't realize its updated, that isn't a problem, since that just means Thread B sleeps when it didn't really need to, and when it wakes up, the value will be correct.

+9  A: 

You could check the gcc documentation. For the current gcc version (4.3.2) it would be chapter 5.47 Built-in functions for atomic memory access - for other gcc versions please check your docs. It should be in chapter 5- Extensions to the C Language Family.

Incidentally, the C compiler makes absolutely no guarantee as to simple store operations being atomic. You cannot rely on that assumption. In order for a machine opcode to be executed atomically, it needs the LOCK prefix.

Mihai Limbășan
Moreover, this built-in functions for atomic memory access are also supported by ICC (in case you intend to be compiler portable).For GCC, I think atomic functions are supported since 4.1 so be sure to have some #ifdef to ensure gcc or icc version!
claferri
+1  A: 

AFAIK, you can't prefix MOV instructions with LOCK; this is allowed only for RMW operations. But if he does use a simple store, he might also need a memory barrier, which is implicit with mutex, as well as with instructions that allow LOCK.

zvrba
+2  A: 

On x86 and most other architectures, aligned 4-byte reads and writes are always atomic. The optimizer may skip/reorder reads and writes within a single thread, though.

What you want to do is inform the compiler that other threads may have touched this memory location. (A side effect of pthread_mutex_lock is telling the compiler that other threads may have touched any part of memory.) You may see volatile recommended, but this not in the C specification, and GCC doesn't interpret volatile that way.

asm("" : "=m" (variable));
frame->variable = variable;

is a GCC-specific mechanism to say that "variable has been written to, reload it".

ephemient
Beyond that, the processor's cache may hide or reorder reads and writes with respect to other processors... so a memory fence is needed. pthread_mutex_lock provides this, but it is very architecture-dependent.
ephemient
+3  A: 

Up to a certain point, atomic operations in C were provided straight from the kernel sources via the atomic.h header.

However, having kernel headers being used directly in user-space code is a very bad practice, so the atomic.h header file was removed some time ago. Instead we ca now make use of the "GCC Atomic Builtins" which are a far better and more reliable approach.

There is a very good explanation provided by Tudor Golubenco on his blog. He even provides a drop-in replacement for the initial atomic.h file, in case you have some code that needs it.

Unfortunately I'm new to stackoverflow, so I can only use one link in my comments, so check Tudor's post and get enlightened.

Valeriu Paloş
A: 

As i can see, you're using gnu platform for development, so it's safe to say that glic provides a datatype int ranged with atomic capabilities, 'sig_atomic_t' . So this approach can assure you atomic operations at kernel levels. not gcc levels.

erick2red