最終更新日時:
が更新

履歴 編集

function template
<atomic>

std::atomic_thread_fence(C++11)

namespace std {
  extern "C" void atomic_thread_fence(memory_order order) noexcept;
}

概要

アトミック操作に対する、補完的なメモリフェンスを提供する。

効果

この関数は、弱いmemory_orderが指定されたアトミック操作の前後に指定することで、より強いmemory_orderを指定した場合と似たような振る舞いをさせる効果を持つ。 たとえば、aatomic<int>型の変数とするとき、下記2種類の処理はほぼ同等の振る舞いをする。

// relaxed操作 + releaseフェンス
std::atomic_thread_fence(std::memory_order_release);
a.store(42, std::memory_order_relaxed);

// release操作
a.store(42, std::memory_order_release);

ただし、後者のほうがより効率的な機械語命令へとコンパイルされる可能性が高い。より詳しい議論についてはN2176などを参照のこと。 同様に、下記2種類の処理はほぼ同等の振る舞いをする。

// relaxed操作 + acquireフェンス
int i = a.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);

// acquireフェンス
int i = a.load(std::memory_order_acquire);

またメモリフェンスのmemory_orderとして memory_order_seq_cst が指定された場合は、異なるatomic変数への操作間に順序一貫性を与える。 以下に例を挙げる。

// 初期値
std::atomic<int> a(0), b(0);

// Thread 1:
a.store(1, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
b.store(1, std::memory_order_relaxed);
int i = b.load(std::memory_order_relaxed);

// Thread 2:
b.store(0, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
int j = a.load(std::memory_order_relaxed);

// 結果
assert(i == 1 || j == 1); // すなわち、i と j が共に0となることはない。

この例では、Thread 1, 2 にあるseq_cstフェンスのいずれか一方でも欠けると (i == 0 && j == 0) という結果が起こりうる。そして、acquire, releaseacq_relフェンスではseq_cstフェンスの代用にはならない。

それぞれのメモリオーダーは以下に示すフェンスとして機能する:

メモリオーダー フェンス
memory_order_relaxed 何も行わない
memory_order_acquire
memory_order_consume
acquireフェンス
memory_order_release releaseフェンス
memory_order_acq_rel acquireフェンスとreleaseフェンスの両方
memory_order_seq_cst acquireフェンスとreleaseフェンスの両方に加え、順序一貫性も与える

戻り値

なし

例外

投げない

#include <iostream>
#include <atomic>
#include <thread>
int data;
std::atomic<bool> ready(false);

void f()
{
  while (!ready.load(std::memory_order_relaxed)) {
  }
  std::atomic_thread_fence(std::memory_order_acquire);

  // atomic変数readyへのstore/load操作とatomic_thread_fenceの効果により、
  // mainスレッドでの "data = 3" の結果が、ここで可視となることが保証される。
  std::cout << data << std::endl;
}

int main()
{
  std::thread t(f);

  data = 3;
  std::atomic_thread_fence(std::memory_order_release);
  ready.store(true, std::memory_order_relaxed);

  t.join();
}

出力

3

バージョン

言語

  • C++11

処理系

参照