Atomic Operations

## Atomic Operations Atomic Operations — basic atomic integer and pointer operations |

## Synopsis

    #include <glib.h>

    gint                g_atomic_int_get                    (volatile gint *atomic);
    void                g_atomic_int_set                    (volatile gint *atomic,
                                                             gint newval);
    void                g_atomic_int_inc                    (gint *atomic);
    gboolean            g_atomic_int_dec_and_test           (gint *atomic);
    gboolean            g_atomic_int_compare_and_exchange   (volatile gint *atomic,
                                                             gint oldval,
                                                             gint newval);
    gint                g_atomic_int_add                    (volatile gint *atomic,
                                                             gint val);
    guint               g_atomic_int_and                    (volatile guint *atomic,
                                                             guint val);
    guint               g_atomic_int_or                     (volatile guint *atomic,
                                                             guint val);
    guint               g_atomic_int_xor                    (volatile guint *atomic,
                                                             guint val);

    gpointer            g_atomic_pointer_get                (volatile void *atomic);
    void                g_atomic_pointer_set                (volatile void *atomic,
                                                             gpointer newval);
    gboolean            g_atomic_pointer_compare_and_exchange
                                                            (volatile void *atomic,
                                                             gpointer oldval,
                                                             gpointer newval);
    gssize              g_atomic_pointer_add                (volatile void *atomic,
                                                             gssize val);
    gsize               g_atomic_pointer_and                (volatile void *atomic,
                                                             gsize val);
    gsize               g_atomic_pointer_or                 (volatile void *atomic,
                                                             gsize val);
    gsize               g_atomic_pointer_xor                (volatile void *atomic,
                                                             gsize val);

    gint                g_atomic_int_exchange_and_add       (volatile gint *atomic,
                                                             gint val);

## Description

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.

On GCC, these macros are implemented using GCC intrinsic operations. On non-GCC compilers they will evaluate to function calls to functions implemented by GLib.

If GLib itself was compiled with GCC then these functions will again be implemented by the GCC intrinsics. On Windows without GCC, the interlocked API is used to implement the functions.

With non-GCC compilers on non-Windows systems, the functions are currently incapable of implementing true atomic operations -- instead, they fallback to holding a global lock while performing the operation. This provides atomicity between the threads of one process, but not between separate processes. For this reason, one should exercise caution when attempting to use these options on shared memory regions.

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.

## Details

### g_atomic_int_get ()

    gint                g_atomic_int_get                    (volatile gint *atomic);

Gets the current value of `atomic`.

This call acts as a full compiler and hardware memory barrier (before the get).

`atomic` : | a pointer to a gint or guint
Returns : | the value of the integer

Since 2.4

### g_atomic_int_set ()

    void                g_atomic_int_set                    (volatile gint *atomic,
                                                             gint newval);

Sets the value of `atomic` to `newval`.

This call acts as a full compiler and hardware memory barrier (after the set).

`atomic` : | a pointer to a gint or guint
`newval` : | a new value to store

Since 2.4

### g_atomic_int_inc ()

    void                g_atomic_int_inc                    (gint *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.

`atomic` : | a pointer to a gint or guint

Since 2.4

### g_atomic_int_dec_and_test ()

    gboolean            g_atomic_int_dec_and_test           (gint *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.

`atomic` : | a pointer to a gint or guint
Returns : | `TRUE` if the resultant value is zero

Since 2.4

### g_atomic_int_compare_and_exchange ()

    gboolean            g_atomic_int_compare_and_exchange   (volatile gint *atomic,
                                                             gint oldval,
                                                             gint 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.

`atomic` : | a pointer to a gint or guint
`oldval` : | the value to compare with
`newval` : | the value to conditionally replace with
Returns : | `TRUE` if the exchange took place

Since 2.4

### g_atomic_int_add ()

    gint                g_atomic_int_add                    (volatile gint *atomic,
                                                             gint 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).

`atomic` : | a pointer to a gint or guint
`val` : | the value to add
Returns : | the value of `atomic` before the add, signed

Since 2.4

### g_atomic_int_and ()

    guint               g_atomic_int_and                    (volatile guint *atomic,
                                                             guint 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; }`

`atomic` : | a pointer to a gint or guint
`val` : | the value to 'and'
Returns : | the value of `atomic` before the operation, unsigned

Since 2.30

### g_atomic_int_or ()

    guint               g_atomic_int_or                     (volatile guint *atomic,
                                                             guint 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.

`atomic` : | a pointer to a gint or guint
`val` : | the value to 'or'
Returns : | the value of `atomic` before the operation, unsigned

Since 2.30

### g_atomic_int_xor ()

    guint               g_atomic_int_xor                    (volatile guint *atomic,
                                                             guint 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.

`atomic` : | a pointer to a gint or guint
`val` : | the value to 'xor'
Returns : | the value of `atomic` before the operation, unsigned

Since 2.30

### g_atomic_pointer_get ()

    gpointer            g_atomic_pointer_get                (volatile void *atomic);

Gets the current value of `atomic`.

This call acts as a full compiler and hardware memory barrier (before the get).

`atomic` : | a pointer to a gpointer-sized value
Returns : | the value of the pointer

Since 2.4

### g_atomic_pointer_set ()

    void                g_atomic_pointer_set                (volatile void *atomic,
                                                             gpointer newval);

Sets the value of `atomic` to `newval`.

This call acts as a full compiler and hardware memory barrier (after the set).

`atomic` : | a pointer to a gpointer-sized value
`newval` : | a new value to store

Since 2.4

### g_atomic_pointer_compare_and_exchange ()

    gboolean            g_atomic_pointer_compare_and_exchange
                                                            (volatile void *atomic,
                                                             gpointer oldval,
                                                             gpointer 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.

`atomic` : | a pointer to a gpointer-sized value
`oldval` : | the value to compare with
`newval` : | the value to conditionally replace with
Returns : | `TRUE` if the exchange took place

Since 2.4

### g_atomic_pointer_add ()

    gssize              g_atomic_pointer_add                (volatile 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.

`atomic` : | a pointer to a gpointer-sized value
`val` : | the value to add
Returns : | the value of `atomic` before the add, signed

Since 2.30

### g_atomic_pointer_and ()

    gsize               g_atomic_pointer_and                (volatile 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.

`atomic` : | a pointer to a gpointer-sized value
`val` : | the value to 'and'
Returns : | the value of `atomic` before the operation, unsigned

Since 2.30

### g_atomic_pointer_or ()

    gsize               g_atomic_pointer_or                 (volatile 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.

`atomic` : | a pointer to a gpointer-sized value
`val` : | the value to 'or'
Returns : | the value of `atomic` before the operation, unsigned

Since 2.30

### g_atomic_pointer_xor ()

    gsize               g_atomic_pointer_xor                (volatile 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.

`atomic` : | a pointer to a gpointer-sized value
`val` : | the value to 'xor'
Returns : | the value of `atomic` before the operation, unsigned

Since 2.30

### g_atomic_int_exchange_and_add ()

    gint                g_atomic_int_exchange_and_add       (volatile gint *atomic,
                                                             gint 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.

`atomic` : | a pointer to a gint
`val` : | the value to add
Returns : | the value of `atomic` before the add, signed

Since 2.4

## See Also

GMutex