Atomic

The following is a collection of compiler macros to provide atomic access to integer and pointer-sized values.

The macros that have 'int' in the name will operate on pointers to gint and guint. The macros with 'pointer' in the name will operate on pointers to any pointer-sized value, including gsize. There is no support for 64bit operations on platforms with 32bit pointers because it is not generally possible to perform these operations atomically.

The get, set and exchange operations for integers and pointers nominally operate on gint and gpointer, respectively. Of the arithmetic operations, the 'add' operation operates on (and returns) signed integer values (gint and gssize) and the 'and', 'or', and 'xor' operations operate on (and return) unsigned integer values (guint and gsize).

All of the operations act as a full compiler and (where appropriate) hardware memory barrier. Acquire and release or producer and consumer barrier semantics are not available through this API.

It is very important that all accesses to a particular integer or pointer be performed using only this API and that different sizes of operation are not mixed or used on overlapping memory regions. Never read or assign directly from or to a value -- always use this API.

For simple reference counting purposes you should use g_atomic_int_inc() and g_atomic_int_dec_and_test(). Other uses that fall outside of simple reference counting patterns are prone to subtle bugs and occasionally undefined behaviour. It is also worth noting that since all of these operations require global synchronisation of the entire machine, they can be quite slow. In the case of performing multiple atomic operations it can often be faster to simply acquire a mutex lock around the critical area, perform the operations normally and then release the lock.

Members

Static functions

intAdd
int intAdd(int* atomic, int val)

Atomically adds val to the value of atomic. Think of this operation as an atomic version of { tmp = *atomic; *atomic += val; return tmp; } This call acts as a full compiler and hardware memory barrier. Before version 2.30, this function did not return a value (but g_atomic_int_exchange_and_add() did, and had the same meaning). Since 2.4

intAnd
uint intAnd(uint* atomic, uint val)

Performs an atomic bitwise 'and' of the value of atomic and val, storing the result back in atomic. This call acts as a full compiler and hardware memory barrier. Think of this operation as an atomic version of { tmp = *atomic; *atomic = val; return tmp; } Since 2.30

intCompareAndExchange
int intCompareAndExchange(int* atomic, int oldval, int newval)

Compares atomic to oldval and, if equal, sets it to newval. If atomic was not equal to oldval then no change occurs. This compare and exchange is done atomically. Think of this operation as an atomic version of { if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; } This call acts as a full compiler and hardware memory barrier. Since 2.4

intDecAndTest
int intDecAndTest(int* atomic)

Decrements the value of atomic by 1. Think of this operation as an atomic version of { *atomic -= 1; return (*atomic == 0); } This call acts as a full compiler and hardware memory barrier. Since 2.4

intExchangeAndAdd
int intExchangeAndAdd(int* atomic, int val)

Warning g_atomic_int_exchange_and_add has been deprecated since version 2.30 and should not be used in newly-written code. Use g_atomic_int_add() instead. This function existed before g_atomic_int_add() returned the prior value of the integer (which it now does). It is retained only for compatibility reasons. Don't use this function in new code. Since 2.4

intGet
int intGet(int* atomic)

Gets the current value of atomic. This call acts as a full compiler and hardware memory barrier (before the get). Since 2.4

intInc
void intInc(int* atomic)

Increments the value of atomic by 1. Think of this operation as an atomic version of { *atomic += 1; } This call acts as a full compiler and hardware memory barrier. Since 2.4

intOr
uint intOr(uint* atomic, uint val)

Performs an atomic bitwise 'or' of the value of atomic and val, storing the result back in atomic. Think of this operation as an atomic version of { tmp = *atomic; *atomic |= val; return tmp; } This call acts as a full compiler and hardware memory barrier. Since 2.30

intSet
void intSet(int* atomic, int newval)

Sets the value of atomic to newval. This call acts as a full compiler and hardware memory barrier (after the set). Since 2.4

intXor
uint intXor(uint* atomic, uint val)

Performs an atomic bitwise 'xor' of the value of atomic and val, storing the result back in atomic. Think of this operation as an atomic version of { tmp = *atomic; *atomic ^= val; return tmp; } This call acts as a full compiler and hardware memory barrier. Since 2.30

pointerAdd
gssize pointerAdd(void* atomic, gssize val)

Atomically adds val to the value of atomic. Think of this operation as an atomic version of { tmp = *atomic; *atomic += val; return tmp; } This call acts as a full compiler and hardware memory barrier. Since 2.30

pointerAnd
gsize pointerAnd(void* atomic, gsize val)

Performs an atomic bitwise 'and' of the value of atomic and val, storing the result back in atomic. Think of this operation as an atomic version of { tmp = *atomic; *atomic = val; return tmp; } This call acts as a full compiler and hardware memory barrier. Since 2.30

pointerCompareAndExchange
int pointerCompareAndExchange(void* atomic, void* oldval, void* newval)

Compares atomic to oldval and, if equal, sets it to newval. If atomic was not equal to oldval then no change occurs. This compare and exchange is done atomically. Think of this operation as an atomic version of { if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; } This call acts as a full compiler and hardware memory barrier. Since 2.4

pointerGet
void* pointerGet(void* atomic)

Gets the current value of atomic. This call acts as a full compiler and hardware memory barrier (before the get). Since 2.4

pointerOr
gsize pointerOr(void* atomic, gsize val)

Performs an atomic bitwise 'or' of the value of atomic and val, storing the result back in atomic. Think of this operation as an atomic version of { tmp = *atomic; *atomic |= val; return tmp; } This call acts as a full compiler and hardware memory barrier. Since 2.30

pointerSet
void pointerSet(void* atomic, void* newval)

Sets the value of atomic to newval. This call acts as a full compiler and hardware memory barrier (after the set). Since 2.4

pointerXor
gsize pointerXor(void* atomic, gsize val)

Performs an atomic bitwise 'xor' of the value of atomic and val, storing the result back in atomic. Think of this operation as an atomic version of { tmp = *atomic; *atomic ^= val; return tmp; } This call acts as a full compiler and hardware memory barrier. Since 2.30

Meta