Thread-safe atomic operations in gcc
Asked Answered
P

5

17

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.

Photoluminescence answered 3/10, 2008 at 6:44 Comment(3)
Since kernel 2.6, the cost of a mutex is almost nothing when the mutex is free. Anyway, "__sync_lock_test_and_set" (since gcc 4.1) should do the trick, this is not the only function that could be used in this case.Cacodyl
__atomic_store or __atomic_store_n seems more appropriate btw.Cacodyl
Does this answer your question? Are there functions for performing atomic operations in the standard library?Udo
S
16

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.

Sum answered 3/10, 2008 at 6:53 Comment(2)
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!Cacodyl
So in case of concurrent access, __sync_add_and_fetch is not reliable ? and we have to use lock addx directly with assembly inlining ?Bacchanal
S
16

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.

Substage answered 4/2, 2010 at 20:4 Comment(0)
J
4

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".

Jackjackadandy answered 4/10, 2008 at 22:17 Comment(1)
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.Jackjackadandy
T
1

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.

Triggerhappy answered 3/10, 2008 at 7:19 Comment(0)
P
0

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.

Payee answered 4/2, 2010 at 20:27 Comment(1)
sig_atomic_t is only atomic with respect to signals. It is not thread-safe.Diapason

© 2022 - 2024 — McMap. All rights reserved.