C++11多线程-原子操作(1)

前面我们讲了C++11下的多线程及相关操作,这些操作在绝大多数情况下应该够用了。但在某些极端场合,如需要高性能的情况下,我们还需要一些更高效的同步手段。本节介绍的原子操作是一种lock free的操作,不需要同步锁,具有很高的性能。在化学中原子不是可分割的最小单位,引申到编程中,原子操作是不可打断的最低粒度操作,是线程安全的。C++11中原子类提供的成员函数都是原子的,是线程安全的。
原子操作中最简单的莫过于atomic_flag,只有两种操作:test and set、clear。我们的原子操作就从这种类型开始。
1. std::atomic_flag C++11中所有的原子类都是不允许拷贝、不允许Move的,atomic_flag也不例外。atomic_flag顾名思议,提供了标志的管理,标志有三种状态:clear、set和未初始化状态。
1.1 atomic_flag实例化 缺省情况下atomic_flag处于未初始化状态。除非初始化时使用了ATOMIC_FLAG_INIT宏,则此时atomic_flag处于clear状态。
1.2 std::atomic_flag::clear 调用该函数将会把atomic_flag置为clear状态。clear状态您可以理解为bool类型的false,set状态可理解为true状态。clear函数没有任何返回值:

void clear(memory_order m = memory_order_seq_cst) volatile noexcept; void clear(memory_order m = memory_order_seq_cst) noexcept;

对于memory_order我们会在后面的章节中详细介绍它,现在先列出其取值及简单释义
序号 意义
1 memory_order_relaxed 宽松模型,不对执行顺序做保证
2 memory_order_consume 当前线程中,满足happens-before原则。
当前线程中该原子的所有后续操作,必须在本条操作完成之后执行
3 memory_order_acquire 当前线程中,读操作满足happens-before原则。
所有后续的读操作必须在本操作完成后执行
4 memory_order_release 当前线程中,写操作满足happens-before原则。
所有后续的写操作必须在本操作完成后执行
5 memory_order_acq_rel 当前线程中,同时满足memory_order_acquire和memory_order_release
6 memory_order_seq_cst 最强约束。全部读写都按顺序执行
1.3 test_and_set 该函数会检测flag是否处于set状态,如果不是,则将其设置为set状态,并返回false;否则返回true。
C++11多线程-原子操作(1)
文章图片

test_and_set是典型的 read-modify-write(RMW)模型,保证多线程环境下只被设置一次。下面代码通过10个线程,模拟了一个计数程序,第一个完成计数的会打印"win"。
#include// atomic_flag #include // std::cout, std::endl #include // std::list #include // std::threadvoid race(std::atomic_flag &af, int id, int n) { for (int i = 0; i < n; i++) { } // 第一个完成计数的打印:Win if (!af.test_and_set()) { printf("%s[%d] win!!!\n", __FUNCTION__, id); } }int main() { std::atomic_flag af = ATOMIC_FLAG_INIT; std::list lstThread; for (int i = 0; i < 10; i++) { lstThread.emplace_back(race, std::ref(af), i + 1, 5000 * 10000); }for (std::thread &thr : lstThread) { thr.join(); }return 0; }

程序输出如下(每次运行,可能率先完成的thread不同):
race[7] win!!!

上一篇
C++11多线程-线程局部存储
目录 下一篇
C++11多线程-原子操作(2)
【C++11多线程-原子操作(1)】

    推荐阅读