Like Visual C++, GCC also comes with a set of built-in atomic functions. These differ based on the underlying architecture that the GCC version and the standard library one uses. Since GCC is used on a considerably larger number of platforms and operating systems than VC++, this is definitely a big factor when considering portability.
For example, not every built-in atomic function provided on the x86 platform will be available on ARM, partially due to architectural differences, including variations of the specific ARM architecture. For example, ARMv6, ARMv7, or the current ARMv8, along with the Thumb instruction set, and so on.
Before the C++11 standard, GCC used __sync-prefixed extensions for atomics:
type __sync_fetch_and_add (type *ptr, type value, ...) type __sync_fetch_and_sub (type *ptr, type value, ...) type __sync_fetch_and_or (type *ptr, type value, ...) type __sync_fetch_and_and (type *ptr, type value, ...) type __sync_fetch_and_xor (type *ptr, type value, ...) type __sync_fetch_and_nand (type *ptr, type value, ...)
These operations fetch a value from memory and perform the specified operation on it, returning the value that was in memory. These all use a memory barrier.
type __sync_add_and_fetch (type *ptr, type value, ...) type __sync_sub_and_fetch (type *ptr, type value, ...) type __sync_or_and_fetch (type *ptr, type value, ...) type __sync_and_and_fetch (type *ptr, type value, ...) type __sync_xor_and_fetch (type *ptr, type value, ...) type __sync_nand_and_fetch (type *ptr, type value, ...)
These operations are similar to the first set, except they return the new value after the specified operation.
bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, ...) type __sync_val_compare_and_swap (type *ptr, type oldval, type newval, ...)
These comparison operations will write the new value if the old value matches the provided value. The Boolean variation returns true if the new value has been written.
__sync_synchronize (...)
This function creates a full memory barrier.
type __sync_lock_test_and_set (type *ptr, type value, ...)
This method is actually an exchange operation unlike what the name suggests. It updates the pointer value and returns the previous value. This uses not a full memory barrier, but an acquire barrier, meaning that it does not release the barrier.
void __sync_lock_release (type *ptr, ...)
This function releases the barrier obtained by the previous method.
To adapt to the C++11 memory model, GCC added the __atomic built-in methods, which also changes the API considerably:
type __atomic_load_n (type *ptr, int memorder) void __atomic_load (type *ptr, type *ret, int memorder) void __atomic_store_n (type *ptr, type val, int memorder) void __atomic_store (type *ptr, type *val, int memorder) type __atomic_exchange_n (type *ptr, type val, int memorder) void __atomic_exchange (type *ptr, type *val, type *ret, int memorder) bool __atomic_compare_exchange_n (type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder) bool __atomic_compare_exchange (type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder)
First are the generic load, store, and exchange functions. They are fairly self-explanatory. Load functions read a value in memory, store functions store a value in memory, and exchange functions swap the existing value with a new value. Compare and exchange functions make the swapping conditional.
type __atomic_add_fetch (type *ptr, type val, int memorder) type __atomic_sub_fetch (type *ptr, type val, int memorder) type __atomic_and_fetch (type *ptr, type val, int memorder) type __atomic_xor_fetch (type *ptr, type val, int memorder) type __atomic_or_fetch (type *ptr, type val, int memorder) type __atomic_nand_fetch (type *ptr, type val, int memorder)
These functions are essentially the same as in the old API, returning the result of the specific operation.
type __atomic_fetch_add (type *ptr, type val, int memorder) type __atomic_fetch_sub (type *ptr, type val, int memorder) type __atomic_fetch_and (type *ptr, type val, int memorder) type __atomic_fetch_xor (type *ptr, type val, int memorder) type __atomic_fetch_or (type *ptr, type val, int memorder) type __atomic_fetch_nand (type *ptr, type val, int memorder)
And again, the same functions, updated for the new API. These return the original value (fetch before operation).
bool __atomic_test_and_set (void *ptr, int memorder)
Unlike the similarly named function in the old API, this function performs a real test and set operation instead of the exchange operation of the old API's function, which still requires one to release the memory barrier afterwards. The test is for some defined value.
void __atomic_clear (bool *ptr, int memorder)
This function clears the pointer address, setting it to 0.
void __atomic_thread_fence (int memorder)
A synchronization memory barrier (fence) between threads can be created using this function.
void __atomic_signal_fence (int memorder)
This function creates a memory barrier between a thread and signal handlers within that same thread.
bool __atomic_always_lock_free (size_t size, void *ptr)
The function checks whether objects of the specified size will always create lock-free atomic instructions for the current processor architecture.
bool __atomic_is_lock_free (size_t size, void *ptr)
This is essentially the same as the previous function.