快捷搜索: 王者荣耀 脱发

C++11多线程 内存屏障(fence/atomic_thread_fence)

0 引言

在前述文章中,我有针对C++11种的六种内存序(memory order)进行相应的讲解,其文章如下

如果不补充C++11种关于fence的讲解,那么内存序这部分是不完善的,故此篇文章便是为此而写。

1 fence基本概念

如果C++原子操作库没有规定一组相应的fences,那么这个原子库是不完备的。fence操作在不修改任何数据的情况下强制执行内存排序约束,并且通常与使用 memory_order_relaxed 排序约束的原子操作相结合。

fence是全局操作,会影响执行fence的线程中其他原子操作的顺序。 fence通常也被称为内存屏障,它们之所以得名,是因为它们在代码中放置了一条特定操作无法跨越的屏障。

C++中支持两种类型的fence:std::atomic_thread_fence 和 a std::atomic_signal_fence.

本文仅仅讲解std::atomic_thread_fence!

std::atomic_thread_fence 防止特定操作越过fence。 std::atomic_thread_fence 不需要原子变量。

上述中,特定的操作可归为如下四类

    LoadLoad: 一个load操作后跟一个load LoadStore: 一个load操作后跟一个store StoreLoad: 一个store操作后跟一个load操作 StoreStore: 一个store操作后跟一个load操作

2 fence分类

C++11中提供了三种fences,分别为full fence, acquire fence 和 release fence.

Full Fence:

std::atomic_thread_fence() 默认为full fence,如果该fence放置在任意两个操作之间,那么可以防止这两个操作被重排序。注意:针对StoreLoad操作,其不能生效

其行为如下所示

Acquire Fence:

std::atomic_thread_fence(std::memory_order_acquire)防止在其前面的read操作被fence后面的读写操作重排序

其行为如下所示

Release Fence:

std::atomic_thread_fence(std::memory_order_release) 防止fence之后的写操作被fence之前的读或写操作重新排序

其行为如下所示

总体而言,三种fences针对四种操作组合的作用如下所示

 3 示例代码

本章示例代码来自《C++ Concurrency in action》相应章节

#include <atomic>
#include <thread>
#include <assert.h>

std::atomic<bool> x,y;
std::atomic<int> z;
void write_x_then_y() {
  x.store(true,std::memory_order_relaxed); // 1
  std::atomic_thread_fence(std::memory_order_release); // 2
  y.store(true,std::memory_order_relaxed); // 3
}

void read_y_then_x() {
  while(!y.load(std::memory_order_relaxed)); // 4
  std::atomic_thread_fence(std::memory_order_acquire); // 5
  if(x.load(std::memory_order_relaxed)) { // 6
    ++z; 
  }

}

int main() {
  x=false;
  y=false;
  z=0;
  std::thread a(write_x_then_y);
  std::thread b(read_y_then_x);
  a.join();
  b.join();
  assert(z.load()!=0); // 7

  return 0;
}

上述代码中 注释7 处的assert永远不会触发。

具体原因可参考如下所示

也即,std::atomic_thread_fence(std::memory_order_release)的release操作同步于其acquire操作,而x的store操作happend-before std::atomic_thread_fence(std::memory_order_release),因此其happen-before x的load操作。

4 总结

本文初步介绍了C++11中的fence概念及其基本使用,通过本篇文章可以加深对相应fence的理解。

参考:

经验分享 程序员 微信小程序 职场和发展