# std::atomic_thread_fence

From cppreference.com
< cpp‎ | atomic

Defined in header `<atomic>` |  |
extern "C" void atomic_thread_fence( std::memory_order order ) noexcept; |  | (since C++11)

Establishes memory synchronization ordering of non-atomic and relaxed atomic accesses, as instructed by `order`, without an associated atomic operation.

#### Fence-atomic synchronization

A release fence F in thread A synchronizes-with atomic acquire operation Y in thread B, if

- there exists an atomic store X (with any memory order)
- Y reads the value written by X (or the value would be written by release sequence headed by X if X were a release operation)
- F is sequenced-before X in thread A

In this case, all non-atomic and relaxed atomic stores that are sequenced-before F in thread A will happen-before all non-atomic and relaxed atomic loads from the same locations made in thread B after Y.

#### Atomic-fence synchronization

An atomic release operation X in thread A synchronizes-with an acquire fence F in thread B, if

- there exists an atomic read Y (with any memory order)
- Y reads the value written by X (or by the release sequence headed by X)
- Y is sequenced-before F in thread B

In this case, all non-atomic and relaxed atomic stores that are sequenced-before X in thread A will happen-before all non-atomic and relaxed atomic loads from the same locations made in thread B after F.

#### Fence-fence synchronization

A release fence FA in thread A synchronizes-with an acquire fence FB in thread B, if

- There exists an atomic object M,
- There exists an atomic write X (with any memory order) that modifies M in thread A
- FA is sequenced-before X in thread A
- There exists an atomic read Y (with any memory order) in thread B
- Y reads the value written by X (or the value would be written by release sequence headed by X if X were a release operation)
- Y is sequenced-before FB in thread B

In this case, all non-atomic and relaxed atomic stores that are sequenced-before FA in thread A will happen-before all non-atomic and relaxed atomic loads from the same locations made in thread B after FB

### Parameters

order | - | the memory ordering executed by this fence

### Return value

(none)

### Notes

`atomic_thread_fence` imposes stronger synchronization constraints than an atomic store operation with the same std::memory_order. While an atomic store-release operation prevents all preceding writes from moving past the store-release, an `atomic_thread_fence` with `memory_order_release` ordering prevents all preceding writes from moving past all subsequent stores.

Fence-fence synchronization can be used to add synchronization to a sequence of several relaxed atomic operations, for example

    //Global
    std::string computation(int);
    void print( std::string );

    std::atomic<int> arr[3] = { -1, -1, -1 };
    std::string data[1000] //non-atomic data

    // Thread A, compute 3 values
    void ThreadA( int v0, int v1, int v2 )
    {
    //assert( 0 <= v0, v1, v2 < 1000 );
    data[v0] = computation(v0);
    data[v1] = computation(v1);
    data[v2] = computation(v2);
    std::atomic_thread_fence(std::memory_order_release);
    std::atomic_store_explicit(&arr[0], v0, std::memory_order_relaxed);
    std::atomic_store_explicit(&arr[1], v1, std::memory_order_relaxed);
    std::atomic_store_explicit(&arr[2], v2, std::memory_order_relaxed);
    }

    // Thread B, prints between 0 and 3 values already computed.
    void ThreadB()
    {
    int v0 = std::atomic_load_explicit(&arr[0], std::memory_order_relaxed);
    int v1 = std::atomic_load_explicit(&arr[1], std::memory_order_relaxed);
    int v2 = std::atomic_load_explicit(&arr[2], std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);
    // v0, v1, v2 might turn out to be -1, some or all of them.
    // otherwise it is safe to read the non-atomic data because of the fences:
    if( v0 != -1 ) { print( data[v0] ); }
    if( v1 != -1 ) { print( data[v1] ); }
    if( v2 != -1 ) { print( data[v2] ); }
    }

### Examples

Scan an array of mailboxes, and process only the ones intended for us, without unnecessary synchronization. This example uses atomic-fence synchronization.

Run this code

    const int num_mailboxes = 32;
    std::atomic<int> mailbox_receiver[num_mailboxes];
    std::string mailbox_data[num_mailboxes];

    // The writer threads update non-atomic shared data
    // and then update mailbox_receiver[i] as follows
    mailbox_data[i] = ...;
    std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release);

    // Reader thread needs to check all mailbox[i], but only needs to sync with one
    for (int i = 0; i < num_mailboxes; ++i) {
        if (std::atomic_load_explicit(&mailbox_receiver[i], std::memory_order_relaxed) == my_id) {
            std::atomic_thread_fence(std::memory_order_acquire); // synchronize with just one writer
            do_work( mailbox_data[i] ); // guaranteed to observe everything done in the writer thread before
                        // the atomic_store_explicit()
        }
     }

### See also

memory_order (C++11) | defines memory ordering constraints for the given atomic operation (enum)
atomic_signal_fence (C++11) | fence between a thread and a signal handler executed in the same thread (function)

Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/atomic/atomic_thread_fence&oldid=104280"