命名空间
变体
操作

std::atomic_thread_fence

来自 cppreference.cn
< cpp‎ | atomic
 
 
并发支持库
线程
(C++11)
(C++20)
this_thread 命名空间
(C++11)
(C++11)
(C++11)
协同取消
互斥
(C++11)
通用锁管理
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
条件变量
(C++11)
信号量
闩锁和屏障
(C++20)
(C++20)
期物
(C++11)
(C++11)
(C++11)
(C++11)
安全回收
(C++26)
危害指针
原子类型
(C++11)
(C++20)
原子类型的初始化
(C++11)(在 C++20 中弃用)
(C++11)(在 C++20 中弃用)
内存顺序
(C++11)(在 C++26 中弃用)
atomic_thread_fence
(C++11)
原子操作的自由函数
原子标志的自由函数
 
定义于头文件 <atomic>
extern "C" void atomic_thread_fence( std::memory_order order ) noexcept;
(自 C++11 起)

根据 order 的指示,建立非原子和宽松原子访问的内存同步顺序,而无需关联的原子操作。 但请注意,如下所述,至少需要一个原子操作来建立同步。

目录

[[编辑段落]] 栅栏-原子同步

如果满足以下条件,线程 A 中的释放栅栏 F 与线程 B 中的原子获取操作 Y 同步:

  • 存在原子存储 X(具有任何内存顺序),
  • Y 读取由 X 写入的值(或者如果 X 是释放操作,则读取由以 X 开头的释放序列将写入的值),
  • F 在线程 A 中先于 X 排序。

在这种情况下,线程 A 中 先于 F 排序的所有非原子和宽松原子存储将 先于 线程 B 中在 Y 之后从相同位置进行的所有非原子和宽松原子加载。

[[编辑段落]] 原子-栅栏同步

如果满足以下条件,线程 A 中的原子释放操作 X 与线程 B 中的获取栅栏 F 同步:

  • 存在原子读取 Y(具有任何内存顺序),
  • Y 读取由 X 写入的值(或由以 X 开头的释放序列写入的值),
  • Y 在线程 B 中先于 F 排序。

在这种情况下,线程 A 中 先于 X 排序的所有非原子和宽松原子存储将 先于 线程 B 中在 F 之后从相同位置进行的所有非原子和宽松原子加载。

[[编辑段落]] 栅栏-栅栏同步

如果满足以下条件,线程 A 中的释放栅栏 FA 与线程 B 中的获取栅栏 FB 同步:

  • 存在原子对象 M,
  • 存在原子写入 X(具有任何内存顺序)在线程 A 中修改 M,
  • FA 在线程 A 中先于 X 排序,
  • 线程 B 中存在原子读取 Y(具有任何内存顺序),
  • Y 读取由 X 写入的值(或者如果 X 是释放操作,则读取由以 X 开头的释放序列将写入的值),
  • Y 在线程 B 中先于 FB 排序。

在这种情况下,线程 A 中 先于 FA 排序的所有非原子和宽松原子存储将 先于 线程 B 中在 FB 之后从相同位置进行的所有非原子和宽松原子加载。

[[编辑段落]] 参数

order - 由此栅栏执行的内存顺序

[[编辑段落]] 返回值

(无)

[[编辑段落]] 注释

在 x86(包括 x86-64)上,atomic_thread_fence 函数不发出 CPU 指令,仅影响编译时代码移动,但 std::atomic_thread_fence(std::memory_order_seq_cst) 除外。

atomic_thread_fence 施加的同步约束比具有相同 std::memory_order 的原子存储操作更强。 虽然原子存储-释放操作阻止所有先前的读取和写入移动到存储-释放之后,但具有 std::memory_order_release 排序的 atomic_thread_fence 阻止所有先前的读取和写入移动到所有后续存储之后。

栅栏-栅栏同步可用于向一系列宽松原子操作添加同步,例如

// 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 文档 关于 atomic_thread_fence