栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

目录

0 引言

1 fence基本概念

2 fence分类

 3 示例代码

4 总结


0 引言

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

C++11多线程 内存序(std::memory_order_seq_cst )

C++11多线程 内存序(std::memory_order_consume)

C++11多线程 内存序(std::memory_order_acquire/release)

C++11多线程 内存序(std::memory_order_relaxed)

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

本文主要讲解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 
#include 
#include 

std::atomic x,y;
std::atomic 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的理解。

参考:

Acquire and Release Fences

C++ Concurrency in Action, Second Edition

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/938607.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号