std::atomic_thread_fence
Определено в заголовочном файле <atomic> | ||
|---|---|---|
extern "C" void atomic_thread_fence( std::memory_order order ) noexcept; | (начиная с C++11) |
Устанавливает порядок синхронизации памяти для неатомарных и атомарных операций с ослабленным порядком, как предписано order, без связанной с ними атомарной операции. Однако обратите внимание: для настройки синхронизации, как описано ниже, необходима хотя бы одна атомарная операция.
Синхронизация «барьер — атомарная операция»
Барьер release F в потоке A синхронизируется с атомарной операцией acquire Y в потоке B, если
- существует атомарная операция записи X (с любым порядком памяти),
- Y считывает значение, записанное X (или значение, которое было бы записано последовательностью release, начинающейся с X, если бы X была операцией release),
- F предшествует X в порядке выполнения в потоке A.
В этом случае все неатомарные и атомарные операции записи с ослабленным порядком, предшествующие F в порядке выполнения в потоке A, происходят до всех неатомарных и атомарных операций чтения с ослабленным порядком из тех же расположений памяти, выполняемых в потоке B после Y.
Синхронизация «атомарная операция — барьер»
Атомарная операция release X в потоке A синхронизируется с барьером acquire F в потоке B, если
- существует атомарная операция чтения Y (с любым порядком памяти),
- Y считывает значение, записанное X (или последовательностью release, начинающейся с X),
- Y предшествует F в порядке выполнения в потоке B.
В этом случае все неатомарные и атомарные операции записи с ослабленным порядком, предшествующие X в порядке выполнения в потоке A, происходят до всех неатомарных и атомарных операций чтения с ослабленным порядком из тех же расположений памяти, выполняемых в потоке B после F.
Синхронизация «барьер — барьер»
Барьер release FA в потоке A синхронизируется с барьером acquire FB в потоке B, если
- существует атомарный объект M,
- существует атомарная операция записи X (с любым порядком памяти), изменяющая M в потоке A,
- FA предшествует X в порядке выполнения в потоке A,
- существует атомарная операция чтения Y (с любым порядком памяти) в потоке B,
- Y считывает значение, записанное X (или значение, которое было бы записано последовательностью release, начинающейся с X, если бы X была операцией release),
- Y предшествует FB в порядке выполнения в потоке B.
В этом случае все неатомарные и атомарные операции записи с ослабленным порядком, предшествующие FA в порядке выполнения в потоке A, происходят до всех неатомарных и атомарных операций чтения с ослабленным порядком из тех же расположений памяти, выполняемых в потоке B после FB.
В зависимости от order эта операция
- не имеет эффектов, если
order == memory_order_relaxed - является барьером acquire, если
order == memory_order_acquire || order == memory_order_consume - является барьером release, если
order == memory_order_release - является одновременно барьером acquire и барьером release, если
order == memory_order_acq_rel - является барьером acquire и release с последовательной согласованностью, если
order == memory_order_seq_cst
Параметры
| order | - | порядок памяти, используемый этим барьером |
Возвращаемое значение
(отсутствует)
Примечания
На x86 (включая x86-64) функции atomic_thread_fence не выдают инструкций процессору и влияют только на перемещение кода на этапе компиляции, за исключением std::atomic_thread_fence(std::memory_order_seq_cst).
atomic_thread_fence накладывает более строгие ограничения на синхронизацию, чем атомарная операция записи с тем же std::memory_order. Если атомарная операция записи release предотвращает перемещение всех предшествующих чтений и записей за эту операцию, то atomic_thread_fence с порядком std::memory_order_release предотвращает перемещение всех предшествующих чтений и записей за все последующие операции записи.
Синхронизацию «барьер — барьер» можно использовать для добавления синхронизации к последовательности из нескольких атомарных операций с ослабленным порядком, например:
// 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]);
}
Пример
Просканировать массив почтовых ящиков и обработать только предназначенные для нас, избегая ненужной синхронизации. В этом примере используется синхронизация «атомарная операция — барьер».
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]);
}
См. также
|
(C++11) | задаёт ограничения на порядок памяти для данной атомарной операции (перечисление) |
|
(C++11) | барьер между потоком и обработчиком сигнала, выполняемым в том же потоке (функция) |
Документация по C для atomic_thread_fence |
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/atomic/atomic_thread_fence