std:: atomic_thread_fence
|
定义于头文件
<atomic>
|
||
|
extern
"C"
void
atomic_thread_fence
(
std::
memory_order
order
)
noexcept
;
|
(C++11 起) | |
建立非原子和宽松原子访问的 内存同步顺序 ,按照 order 指定的方式进行,但不关联具体的原子操作。但请注意,如下文所述,至少需要一个原子操作来建立同步机制。
目录 |
栅栏-原子操作同步
释放栅栏
F
在线程
A
中与线程
B
中的原子
获取操作
Y
实现同步,如果
-
存在一个原子存储操作
X(采用任意内存序), -
Y读取了由X写入的值(或者如果X是释放操作,则读取由 以X为首的释放序列 将要写入的值), -
在线程
A中,F按顺序先于X执行。
在此情况下,线程
A
中所有
顺序先于
F
的非原子操作与宽松原子存储操作,都将
先于
线程
B
中在
Y
之后对相同内存位置执行的所有非原子操作与宽松原子加载操作发生。
原子栅栏同步
当线程
A
中的原子
释放操作
X
与线程
B
中的获取栅栏
F
满足以下条件时,二者建立同步关系:
-
存在一个原子读取操作
Y(采用任意内存序), -
Y读取了由X(或由 以 X 为首的释放序列 )所写入的值, -
在线程
B中,Y按顺序先于F执行。
在此情况下,线程
A
中所有
顺序先于
X
的非原子操作与宽松原子存储操作,将会
先于
线程
B
中在
F
之后对相同内存位置执行的所有非原子操作与宽松原子加载操作发生。
栅栏-栅栏同步
释放栅栏
FA
在线程
A
中与获取栅栏
FB
在线程
B
中实现同步,当
-
存在一个原子对象
M, -
存在一个原子写操作
X(使用任意内存序)在线程A中修改M, -
FA在线程A中按顺序先于X, -
存在一个原子读操作
Y(使用任意内存序)在线程B中, -
Y读取由X写入的值(或者如果X是释放操作,则读取由 以X为首的释放序列 将写入的值), -
Y在线程B中按顺序先于FB。
在此情况下,线程
A
中所有
按序早于
FA
的非原子操作与宽松原子存储操作,将会
先于
线程
B
中在
FB
之后对相同内存位置执行的所有非原子操作与宽松原子加载操作发生。
根据 order 参数值的不同,此调用的效果如下:
- 当 order == std:: memory_order_relaxed 时,无任何效果。
- 当 order == std:: memory_order_acquire 或 order == std:: memory_order_consume 时,为获取栅栏。
- 当 order == std:: memory_order_release 时,为释放栅栏。
- 当 order == std:: memory_order_acq_rel 时,既是释放栅栏也是获取栅栏。
- 当 order == std:: memory_order_seq_cst 时,为顺序一致排序的获取栅栏和释放栅栏。
参数
| 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
会阻止所有先前的读写操作越过所有后续的存储操作。
围栏-围栏同步可用于为一系列多个宽松原子操作添加同步,例如:
// 全局 std::string computation(int); void print(std::string); std::atomic<int> arr[3] = {-1, -1, -1}; std::string data[1000]; //非原子数据 // 线程A,计算3个值 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); } // 线程B,打印0到3个已计算的值 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可能为-1,部分或全部为-1 // 由于栅栏的存在,读取非原子数据是安全的: 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]; // 写入线程先更新非原子共享数据 // 然后按如下方式更新 mailbox_receiver[i]: mailbox_data[i] = ...; std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release); // 读取线程需要检查所有 mailbox[i],但只需与其中一个同步 for (int i = 0; i < num_mailboxes; ++i) if (std::atomic_load_explicit(&mailbox_receiver[i], std::memory_order_relaxed) == my_id) { // 仅与一个写入线程同步 std::atomic_thread_fence(std::memory_order_acquire); // 保证能观察到写入线程在 atomic_store_explicit() 之前完成的所有操作 do_work(mailbox_data[i]); }
参见
|
(C++11)
|
定义给定原子操作的内存排序约束
(枚举) |
|
(C++11)
|
同一线程内线程与信号处理程序之间的栅栏
(函数) |
|
C 文档
关于
atomic_thread_fence
|
|