《C++11 并发指南六.docx》由会员分享,可在线阅读,更多相关《C++11 并发指南六.docx(30页珍藏版)》请在三一办公上搜索。
1、C+11 并发指南六std:atomic 基本介绍 std:atomic 是模板类,一个模板类型为 T 的原子对象中封装了一个类型为 T 的值。 template struct atomic; 原子类型对象的主要特点就是从不同线程访问不会导致数据竞争(data race)。因此从不同线程访问某个原子对象是良性 (well-defined) 行为,而通常对于非原子类型而言,并发访问某个对象会导致未定义 (undifined) 行为发生。 C+11 标准中的基本 std:atomic 模板定义如下: template struct atomic bool is_lock_free const vo
2、latile; bool is_lock_free const; void store(T, memory_order = memory_order_seq_cst) volatile; void store(T, memory_order = memory_order_seq_cst); T load(memory_order = memory_order_seq_cst) const volatile; T load(memory_order = memory_order_seq_cst) const; operator T const volatile; operator T const
3、; T exchange(T, memory_order = memory_order_seq_cst) volatile; T exchange(T, memory_order = memory_order_seq_cst); bool compare_exchange_weak(T &, T, memory_order, memory_order) volatile; bool compare_exchange_weak(T &, T, memory_order, memory_order); bool compare_exchange_strong(T &, T, memory_orde
4、r, memory_order) volatile; bool compare_exchange_strong(T &, T, memory_order, memory_order); bool compare_exchange_weak(T &, T, memory_order = memory_order_seq_cst) volatile; bool compare_exchange_weak(T &, T, memory_order = memory_order_seq_cst); bool compare_exchange_strong(T &, T, memory_order =
5、memory_order_seq_cst) volatile; bool compare_exchange_strong(T &, T, memory_order = memory_order_seq_cst); atomic = default; constexpr atomic(T); atomic(const atomic &) = delete; atomic & operator=(const atomic &) = delete; atomic & operator=(const atomic &) volatile = delete; T operator=(T) volatil
6、e; T operator=(T); ; 另外,C+11 标准库 std:atomic 提供了针对整形(integral)和指针类型的特化实现,分别定义如下: 针对整形(integal)的特化,其中 integal 代表了如下类型char, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, char16_t, char32_t, wchar_t: ? template struct atomic boo
7、l is_lock_free const volatile; bool is_lock_free const; void store(integral, memory_order = memory_order_seq_cst) volatile; void store(integral, memory_order = memory_order_seq_cst); integral load(memory_order = memory_order_seq_cst) const volatile; integral load(memory_order = memory_order_seq_cst)
8、 const; operator integral const volatile; operator integral const; integral exchange(integral, memory_order = memory_order_seq_cst) volatile; integral exchange(integral, memory_order = memory_order_seq_cst); bool compare_exchange_weak(integral&, integral, memory_order, memory_order) volatile; bool c
9、ompare_exchange_weak(integral&, integral, memory_order, memory_order); bool compare_exchange_strong(integral&, integral, memory_order, memory_order) volatile; bool compare_exchange_strong(integral&, integral, memory_order, memory_order); bool compare_exchange_weak(integral&, integral, memory_order =
10、 memory_order_seq_cst) volatile; bool compare_exchange_weak(integral&, integral, memory_order = memory_order_seq_cst); bool compare_exchange_strong(integral&, integral, memory_order = memory_order_seq_cst) volatile; bool compare_exchange_strong(integral&, integral, memory_order = memory_order_seq_cs
11、t); integral fetch_add(integral, memory_order = memory_order_seq_cst) volatile; integral fetch_add(integral, memory_order = memory_order_seq_cst); integral fetch_sub(integral, memory_order = memory_order_seq_cst) volatile; integral fetch_sub(integral, memory_order = memory_order_seq_cst); integral f
12、etch_and(integral, memory_order = memory_order_seq_cst) volatile; integral fetch_and(integral, memory_order = memory_order_seq_cst); integral fetch_or(integral, memory_order = memory_order_seq_cst) volatile; integral fetch_or(integral, memory_order = memory_order_seq_cst); integral fetch_xor(integra
13、l, memory_order = memory_order_seq_cst) volatile; integral fetch_xor(integral, memory_order = memory_order_seq_cst); atomic = default; constexpr atomic(integral); atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; integral o
14、perator=(integral) volatile; integral operator=(integral); integral operator+(int) volatile; integral operator+(int); integral operator-(int) volatile; integral operator-(int); integral operator+ volatile; integral operator+; integral operator- volatile; integral operator-; integral operator+=(integ
15、ral) volatile; integral operator+=(integral); integral operator-=(integral) volatile; integral operator-=(integral); integral operator&=(integral) volatile; integral operator&=(integral); integral operator|=(integral) volatile; integral operator|=(integral); integral operator=(integral) volatile; in
16、tegral operator=(integral); ; 针对指针的特化: ? template struct atomic bool is_lock_free const volatile; bool is_lock_free const; void store(T*, memory_order = memory_order_seq_cst) volatile; void store(T*, memory_order = memory_order_seq_cst); T* load(memory_order = memory_order_seq_cst) const volatile; T
17、* load(memory_order = memory_order_seq_cst) const; operator T* const volatile; operator T* const; T* exchange(T*, memory_order = memory_order_seq_cst) volatile; T* exchange(T*, memory_order = memory_order_seq_cst); bool compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile; bool compar
18、e_exchange_weak(T*&, T*, memory_order, memory_order); bool compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile; bool compare_exchange_strong(T*&, T*, memory_order, memory_order); bool compare_exchange_weak(T*&, T*, memory_order = memory_order_seq_cst) volatile; bool compare_exchang
19、e_weak(T*&, T*, memory_order = memory_order_seq_cst); bool compare_exchange_strong(T*&, T*, memory_order = memory_order_seq_cst) volatile; bool compare_exchange_strong(T*&, T*, memory_order = memory_order_seq_cst); T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst) volatile; T* fetch_add(p
20、trdiff_t, memory_order = memory_order_seq_cst); T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst) volatile; T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst); atomic = default; constexpr atomic(T*); atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; atom
21、ic& operator=(const atomic&) volatile = delete; T* operator=(T*) volatile; T* operator=(T*); T* operator+(int) volatile; T* operator+(int); T* operator-(int) volatile; T* operator-(int); T* operator+ volatile; T* operator+; T* operator- volatile; T* operator-; T* operator+=(ptrdiff_t) volatile; T* o
22、perator+=(ptrdiff_t); T* operator-=(ptrdiff_t) volatile; T* operator-=(ptrdiff_t); ; std:atomic 成员函数 好了,对 std:atomic 有了一个最基本认识之后我们来看 std:atomic 的成员函数吧。 std:atomic 构造函数 std:atomic 的构造函数如下: default (1) initialization (2) atomic noexcept = default; constexpr atomic (T val) noexcept; copy deleted (3) at
23、omic (const atomic&) = delete; 1. 默认构造函数,由默认构造函数创建的 std:atomic 对象处于未初始化(uninitialized)状态,对处于未初始化(uninitialized)状态 std:atomic对象可以由 atomic_init 函数进行初始化。 2. 初始化构造函数,由类型 T初始化一个 std:atomic对象。 3. 拷贝构造函数被禁用。 请看下例: ? #include / std:cout #include / std:atomic, std:atomic_flag, ATOMIC_FLAG_INIT #include / std
24、:thread, std:this_thread:yield #include / std:vector / 由 false 初始化一个 std:atomic 类型的原子变量 std:atomic ready(false); std:atomic_flag winner = ATOMIC_FLAG_INIT; void do_count1m(int id) while (!ready) std:this_thread:yield; / 等待 ready 变为 true. for (volatile int i=0; i1000000; +i) / 计数 if (!winner.test_and
25、_set) std:cout thread # id won!n; int main std:vector threads; std:cout spawning 10 threads that count to 1 million.n; for (int i=1; i=10; +i) threads.push_back(std:thread(count1m,i); ready = true; for (auto& th : threads) th.join; return 0; std:atomic:operator= 函数 std:atomic 的赋值操作函数定义如下: set value
26、(1) T operator= (T val) noexcept; T operator= (T val) volatile noexcept; atomic& operator= (const atomic&) = delete; atomic& operator= (const atomic&) volatile = delete; copy deleted (2) 可以看出,普通的赋值拷贝操作已经被禁用。但是一个类型为 T 的变量可以赋值给相应的原子类型变量,该操作是原子的,内存序(Memory Order) 默认为顺序一致性(std:memory_order_seq_cst),如果需要
27、指定其他的内存序,需使用 std:atomic:store。 ? #include / std:cout #include / std:atomic #include / std:thread, std:this_thread:yield std:atomic foo = 0; void set_foo(int x) foo = x; / 调用 std:atomic:operator=. void print_foo while (foo = 0) / wait while foo = 0 std:this_thread:yield; std:cout foo: foo n; int main
28、 std:thread first(print_foo); std:thread second(set_foo, 10); first.join; second.join; return 0; 基本 std:atomic 类型操作 本节主要介绍基本 std:atomic 类型所具备的操作。我们知道 std:atomic 是模板类,一个模板类型为 T 的原子对象中封装了一个类型为 T 的值。本文一节中也提到了 std:atomic 类模板除了基本类型以外,还针对整形和指针类型做了特化。 特化的 std:atomic 类型支持更多的操作,如 fetch_add, fetch_sub, fetch_
29、and 等。本小节介绍基本 std:atomic 类型所具备的操作: is_lock_free ? bool is_lock_free const volatile noexcept; bool is_lock_free const noexcept; 判断该 std:atomic 对象是否具备 lock-free 的特性。如果某个对象满足 lock-free 特性,在多个线程访问该对象时不会导致线程阻塞。(可能使用某种事务内存transactional memory 方法实现 lock-free 的特性)。 store ? void store (T val, memory_order sy
30、nc = memory_order_seq_cst) volatile noexcept; void store (T val, memory_order sync = memory_order_seq_cst) noexcept; 修改被封装的值,std:atomic:store 函数将类型为 T 的参数 val 复制给原子对象所封装的值。T 是 std:atomic 类模板参数。另外参数 sync 指定内存序(Memory Order),可能的取值如下: Memory Order 值 Memory Order 类型 memory_order_relaxed memory_order_rel
31、ease Relaxed Release memory_order_seq_cst Sequentially consistent 请看下面例子: ? #include / std:cout #include / std:atomic, std:memory_order_relaxed #include / std:thread std:atomic foo(0); / 全局的原子对象 foo void set_foo(int x) foo.store(x, std:memory_order_relaxed); / 设置(store) 原子对象 foo 的值 void print_foo in
32、t x; do x = foo.load(std:memory_order_relaxed); / 读取(load) 原子对象 foo 的值 while (x = 0); std:cout foo: x n; int main std:thread first(print_foo); / 线程 first 打印 foo 的值 std:thread second(set_foo, 10); / 线程 second 设置 foo 的值 first.join; second.join; return 0; load ? T load (memory_order sync = memory_order
33、_seq_cst) const volatile noexcept; T load (memory_order sync = memory_order_seq_cst) const noexcept; 读取被封装的值,参数 sync 设置内存序(Memory Order),可能的取值如下: Memory Order 值 memory_order_relaxed memory_order_consume memory_order_acquire memory_order_seq_cst Memory Order 类型 Relaxed Consume Acquire Sequentially co
34、nsistent 请看下面例子: ? #include / std:cout #include / std:atomic, std:memory_order_relaxed #include / std:thread std:atomic foo(0); / 全局的原子对象 foo void set_foo(int x) foo.store(x, std:memory_order_relaxed); / 设置(store) 原子对象 foo 的值 void print_foo int x; do x = foo.load(std:memory_order_relaxed); / 读取(load
35、) 原子对象 foo 的值 while (x = 0); std:cout foo: x n; int main std:thread first(print_foo); / 线程 first 打印 foo 的值 std:thread second(set_foo, 10); / 线程 second 设置 foo 的值 first.join; second.join; return 0; operator T ? operator T const volatile noexcept; operator T const noexcept; 与 load 功能类似,也是读取被封装的值,operat
36、or T 是类型转换(type-cast)操作,默认的内存序是 std:memory_order_seq_cst,如果需要指定其他的内存序,你应该使用 load 函数。请看下面例子: ? #include / std:cout #include / std:atomic #include / std:thread, std:this_thread:yield std:atomic foo = 0; std:atomic bar = 0; void set_foo(int x) foo = x; void copy_foo_to_bar / 如果 foo = 0,则该线程 yield, / 在
37、foo = 0 时, 实际也是隐含了类型转换操作, / 因此也包含了 operator T const 的调用. while (foo = 0) std:this_thread:yield; / 实际调用了 operator T const, 将foo 强制转换成 int 类型, / 然后调用 operator=. bar = static_cast(foo); void print_bar / 如果 bar = 0,则该线程 yield, / 在 bar = 0 时, 实际也是隐含了类型转换操作, / 因此也包含了 operator T const 的调用. while (bar = 0)
38、std:this_thread:yield; std:cout bar: bar n; int main std:thread first(print_bar); std:thread second(set_foo, 10); std:thread third(copy_foo_to_bar); first.join; second.join; third.join; return 0; exchange T exchange (T val, memory_order sync = memory_order_seq_cst) volatile noexcept; T exchange (T v
39、al, memory_order sync = memory_order_seq_cst) noexcept; 读取并修改被封装的值,exchange 会将 val 指定的值替换掉之前该原子对象封装的值,并返回之前该原子对象封装的值,整个过程是原子的(因此exchange 操作也称为 read-modify-write 操作)。sync参数指定内存序(Memory Order),可能的取值如下: Memory Order 值 memory_order_relaxed memory_order_consume memory_order_acquire memory_order_release m
40、emory_order_acq_rel memory_order_seq_cst Memory Order 类型 Relaxed Consume Acquire Release Acquire/Release Sequentially consistent 请看下面例子,各个线程计数至 1M,首先完成计数任务的线程打印自己的 ID, ? / std:cout / std:atomic / std:thread / std:vector std:atomic ready(false); std:atomic winner(false); void count1m (int id) while (
41、!ready) / wait for the ready signal for (int i = 0; i 1000000; +i) / go!, count to 1 million if (!winner.exchange(true) std:cout thread # id won!n; ; int main std:vector threads; std:cout spawning 10 threads that count to 1 million.n; for (int i = 1; i = 10; +i) threads.push_back(std:thread(count1m,i); ready = true; for (auto& th : threads) th.join; return 0; #include #include #inclu