std::atomic_thread_fence
Определено в заголовочном файле <atomic> |
||
|---|---|---|
extern "C" void atomic_thread_fence( std::memory_order order ) noexcept; |
(с C++11) |
Устанавливает порядок синхронизации памяти для неатомарных и релаксированных атомарных операций, как указано в order, без связанной атомарной операции. Однако следует отметить, что для настройки синхронизации необходима хотя бы одна атомарная операция, как описано ниже.
Синхронизация заграждения-атома
Заграждение выпуска F в потоке A синхронизируется с атомарной операцией захвата Y в потоке B, если
- существует атомарное сохранение X (с любым порядком памяти),
- Y считывает значение, записанное X (или значение, которое было бы записано последовательностью выпуска, возглавляемой X, если X была операцией выпуска),
- F предшествует X в потоке A.
В этом случае все неатомарные и релаксированные атомарные сохранения, которые предшествуют F в потоке A, будут происходить до всех неатомарных и релаксированных атомарных чтений из тех же расположений, выполненных в потоке B после Y.
Синхронизация атомарного заграждения
Атомарная операция выпуска X в потоке A синхронизируется с заграждением захвата F в потоке B, если
- существует атомарное чтение Y (с любым порядком памяти),
- Y считывает значение, записанное X (или значение, которое было бы записано последовательностью выпуска, возглавляемой X),
- Y предшествует F в потоке B.
В этом случае все неатомарные и релаксированные атомарные сохранения, которые предшествуют X в потоке A, будут происходить до всех неатомарных и релаксированных атомарных чтений из тех же расположений, выполненных в потоке B после F.
Синхронизация заграждения-заграждения
Заграждение выпуска FA в потоке A синхронизируется с заграждением захвата FB в потоке B, если
- существует атомарный объект M,
- существует атомарная запись X (с любым порядком памяти), которая изменяет M в потоке A,
- FA предшествует X в потоке A,
- существует атомарное чтение Y (с любым порядком памяти) в потоке B,
- Y считывает значение, записанное X (или значение, которое было бы записано последовательностью выпуска, возглавляемой X, если X была операцией выпуска),
- Y предшествует FB в потоке B.
В этом случае все неатомарные и релаксированные атомарные сохранения, которые предшествуют FA в потоке A, будут происходить до всех неатомарных и релаксированных атомарных чтений из тех же расположений, выполненных в потоке B после FB.
Параметры
| order | - | порядок памяти, выполняемый этим заграждением |
Возвращаемое значение
(ничего)
Примечания
На x86 (включая x86-64), atomic_thread_fence функции не выдают команд процессора и влияют только на перемещение кода на этапе компиляции, за исключением std::atomic_thread_fence(std::memory_order::seq_cst).
atomic_thread_fence накладывает более строгие ограничения синхронизации, чем атомарная операция сохранения с тем же std::memory_order. В то время как атомарная операция сохранения-выпуска предотвращает перемещение всех предшествующих чтений и записей мимо операции сохранения-выпуска, atomic_thread_fence с 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/w/cpp/atomic/atomic_thread_fence