table of contents
- Tumbleweed 2024.07.05-1.3
- Leap-16.0
- Leap-15.6
std::atomic_thread_fence(3) | C++ Standard Libary | std::atomic_thread_fence(3) |
NAME¶
std::atomic_thread_fence - std::atomic_thread_fence
Synopsis¶
Defined in header <atomic>
extern "C" void atomic_thread_fence( std::memory_order order )
(since C++11)
noexcept;
Establishes memory synchronization ordering of non-atomic and relaxed atomic
accesses, as instructed by order, without an associated atomic operation.
Note
however, that at least one atomic operation is required to set up the
synchronization, as described below.
Parameters¶
order - the memory ordering executed by this fence
Return value¶
(none)
Notes¶
On x86 (including x86-64), atomic_thread_fence functions issue no
CPU instructions
and only affect compile-time code motion, except for
std::atomic_thread_fence(std::memory_order::seq_cst).
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 reads and writes from moving past the
store-release, an atomic_thread_fence with memory_order_release ordering
prevents
all preceding reads and 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]);
}
Example¶
Scan an array of mailboxes, and process only the ones intended
for us, without
unnecessary synchronization. This example uses atomic-fence
synchronization.
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)
{
// synchronize with just one writer
std::atomic_thread_fence(std::memory_order_acquire);
// guaranteed to observe everything done in the writer thread
// before the atomic_store_explicit()
do_work(mailbox_data[i]);
}
See also¶
memory_order defines memory ordering constraints for the given
atomic
(C++11) operation
(enum)
atomic_signal_fence fence between a thread and a signal handler executed in
the same
(C++11) thread
(function)
C documentation for
atomic_thread_fence
2024.06.10 | http://cppreference.com |