Thread-safe atomic operations in gcc

2019-03-09 08:11发布

问题:

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.

回答1:

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.



回答2:

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.



回答3:

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



回答4:

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.



回答5:

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.