• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

    最終更新日時(UTC):
    が更新

    履歴 編集

    function
    <atomic>

    std::atomic_thread_fence

    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

    処理系

    参照