原子库为细粒度的原子操作提供组件,允许无锁并发编程。涉及同一对象的每个原子操作,相对于任何其他原子操作是不可分的。原子对象不具有数据竞争(data race)。原子类型对象的主要特点就是从不同线程访问不会导致数据竞争。因此从不同线程访问某个原子对象是良性(well-defined)行为,而通常对于非原子类型而言,并发访问某个对象(如果不做任何同步操作)会导致未定义(undifined)行为发生。

atomic是C++标准程序库中的一个头文件,定义了C++11标准中的一些表示线程、并发控制时原子操作的类与方法等。此头文件主要声明了两大类原子对象:std::atomic和std::atomic_flag,另外还声明了一套C风格的原子类型和与C兼容的原子操作的函数。在多线程并发执行时,原子操作是线程不会被打断的执行片段。一些程序设计更为注重性能和效率,需要开发lock-free的算法和数据结构,这就需要更为底层的原子操作与原子类型。原子类型对象的主要特点就是从不同线程并发访问是良性(well-defined)行为,不会导致竞争危害。与之相反,不做适当控制就并发访问非原子对象则会导致未定义(undifined)行为。

atomic_flag类:是一种简单的原子布尔类型,只支持两种操作:test_and_set(flag=true)和clear(flag=false)。跟std::atomic的其它所有特化类不同,它是锁无关的。结合std::atomic_flag::test_and_set()和std::atomic_flag::clear(),std::atomic_flag对象可以当作一个简单的自旋锁(spin lock)使用。atomic_flag只有默认构造函数,禁用拷贝构造函数,移动构造函数实际上也禁用。如果在初始化时没有明确使用宏ATOMIC_FLAG_INIT初始化,那么新创建的std::atomic_flag对象的状态是未指定的(unspecified),既没有被set也没有被clear;如果使用该宏初始化,该std::atomic_flag对象在创建时处于clear状态。

(1)、test_and_set:返回该std::atomic_flag对象当前状态,检查flag是否被设置,若被设置直接返回true,若没有设置则设置flag为true后再返回false。该函数是原子的。

(2)、clear:清除std::atomic_flag对象的标志位,即设置atomic_flag的值为false。

std::atomic类模板:std::atomic比std::atomic_flag功能更加完善。C++11标准库std::atomic提供了针对bool类型、整形(integral)和指针类型的特化实现。每个std::atomic模板的实例化和完全特化定义一个原子类型。若一个线程写入原子对象,同时另一个线程从它读取,则行为良好定义。而且,对原子对象的访问可以按std::memory_order所指定建立线程间同步,并排序非原子的内存访问。std::atomic可以以任何可平凡复制(Trivially Copyable)的类型T实例化。std::atomic既不可复制亦不可移动。

除了std::atomic和std::atomic_flag外,<atomic>还包括了基于std::atomic_flag类的C风格API和基于std::atomic类模板的C风格API。

与原子对象初始化相关的两个宏:

(1)、ATOMIC_VAR_INIT(val):初始化std::atomic对象。This macro expands to a token sequence suitable to initialize an atomic object (of static storage duration) with a value of val. This macro exists for compatibility with C implementations, in which it is used as a constructor-like function for(default-constructed) atomic objects; In C++, this initialization may be performed directly by the initialization constructor.

(2)、ATOMIC_FLAG_INIT:初始化std::atomic_flag对象。This macro is defined in such a way that it can be used to initialize an object of type atomic_flag to the clear state.

std::atomic:Objects of atomic types contain a value of a particular type (T). The main characteristic of atomic objects is that access to this contained value from different threads cannot cause data races (i.e., doing that is well-defined behavior, with accesses properly sequenced). Generally, for all other objects, the possibility of causing a data race for accessing the same object concurrently qualifies the operation as undefined behavior. Additionally, atomic objects have the ability to synchronize access to other non-atomic objects in their threads by specifying different memory orders.

std::atomic_flag:Atomic flags are boolean atomic objects that support two operations:test-and-set and clear.

下面是从其他文章中copy的<atomic>测试代码,详细内容介绍可以参考对应的reference:

  1. #include "atomic.hpp"
  2. #include <iostream>
  3. #include <atomic>
  4. #include <vector>
  5. #include <thread>
  6. #include <sstream>
  7. namespace atomic {
  8. /
  9. // reference: http://www.cplusplus.com/reference/atomic/atomic/atomic/
  10. std::atomic<bool> ready(false);
  11. // atomic_flag::atomic_flag: Constructs an atomic_flag object
  12. // The atomic_flag is in an unspecified state on construction (either set or clear),
  13. // unless it is explicitly initialized to ATOMIC_FLAG_INIT.
  14. std::atomic_flag winner = ATOMIC_FLAG_INIT;
  15. void count1m(int id)
  16. {
  17. while (!ready) { std::this_thread::yield(); } // wait for the ready signal
  18. for (volatile int i = 0; i < 1000000; ++i) {} // go!, count to 1 million
  19. if (!winner.test_and_set()) { std::cout << "thread #" << id << " won!\n"; }
  20. };
  21. int test_atomic_atomic()
  22. {
  23. // atomic::atomic: Constructs an atomic object
  24. std::vector<std::thread> threads;
  25. std::cout << "spawning 10 threads that count to 1 million...\n";
  26. for (int i = 1; i <= 10; ++i) threads.push_back(std::thread(count1m, i));
  27. ready = true;
  28. for (auto& th : threads) th.join();
  29. return 0;
  30. }
  31. /
  32. // reference: http://www.cplusplus.com/reference/atomic/atomic/compare_exchange_weak/
  33. // a simple global linked list:
  34. struct Node { int value; Node* next; };
  35. std::atomic<Node*> list_head(nullptr);
  36. void append(int val)
  37. { // append an element to the list
  38. Node* oldHead = list_head;
  39. Node* newNode = new Node{ val, oldHead };
  40. // what follows is equivalent to: list_head = newNode, but in a thread-safe way:
  41. while (!list_head.compare_exchange_weak(oldHead, newNode))
  42. newNode->next = oldHead;
  43. }
  44. int test_atomic_compare_exchange_weak()
  45. {
  46. // atomic::compare_exchange_weak: Compares the contents of the atomic object's contained value with expected:
  47. // -if true, it replaces the contained value with val(like store).
  48. // - if false, it replaces expected with the contained value
  49. // spawn 10 threads to fill the linked list:
  50. std::vector<std::thread> threads;
  51. for (int i = 0; i<10; ++i) threads.push_back(std::thread(append, i));
  52. for (auto& th : threads) th.join();
  53. // print contents:
  54. for (Node* it = list_head; it != nullptr; it = it->next)
  55. std::cout << ' ' << it->value;
  56. std::cout << '\n';
  57. // cleanup:
  58. Node* it; while (it = list_head) { list_head = it->next; delete it; }
  59. return 0;
  60. }
  61. ///
  62. // reference: http://www.cplusplus.com/reference/atomic/atomic/exchange/
  63. std::atomic<bool> winner_(false);
  64. void count1m_(int id)
  65. {
  66. while (!ready) {} // wait for the ready signal
  67. for (int i = 0; i<1000000; ++i) {} // go!, count to 1 million
  68. if (!winner_.exchange(true)) { std::cout << "thread #" << id << " won!\n"; }
  69. };
  70. int test_atomic_exchange()
  71. {
  72. // atomic::exchange: Replaces the contained value by val and returns the value it had immediately before
  73. std::vector<std::thread> threads;
  74. std::cout << "spawning 10 threads that count to 1 million...\n";
  75. for (int i = 1; i <= 10; ++i) threads.push_back(std::thread(count1m_, i));
  76. ready = true;
  77. for (auto& th : threads) th.join();
  78. return 0;
  79. }
  80. /
  81. // reference: http://www.cplusplus.com/reference/atomic/atomic/load/
  82. std::atomic<int> foo(0);
  83. void set_foo(int x)
  84. {
  85. foo.store(x, std::memory_order_relaxed); // set value atomically
  86. }
  87. void print_foo()
  88. {
  89. int x;
  90. do {
  91. x = foo.load(std::memory_order_relaxed); // get value atomically
  92. } while (x == 0);
  93. std::cout << "foo: " << x << '\n';
  94. }
  95. int test_atomic_load()
  96. {
  97. // atomic::load: Returns the contained value.
  98. // The operation is atomic and follows the memory ordering specified by sync.
  99. std::thread first(print_foo);
  100. std::thread second(set_foo, 10);
  101. first.join();
  102. second.join();
  103. return 0;
  104. }
  105. // reference: http://www.cplusplus.com/reference/atomic/atomic/operator=/
  106. std::atomic<int> foo_ = 0;
  107. void set_foo_(int x)
  108. {
  109. foo_ = x;
  110. }
  111. void print_foo_()
  112. {
  113. while (foo_ == 0) { // wait while foo_=0
  114. std::this_thread::yield();
  115. }
  116. std::cout << "foo_: " << foo_ << '\n';
  117. }
  118. int test_atomic_operator()
  119. {
  120. // atomic::operator=: Replaces the stored value by val.
  121. // This operation is atomic and uses sequential consistency (memory_order_seq_cst).
  122. // To modify the value with a different memory ordering
  123. std::thread first(print_foo_);
  124. std::thread second(set_foo_, 10);
  125. first.join();
  126. second.join();
  127. return 0;
  128. }
  129. ///
  130. // reference: http://www.cplusplus.com/reference/atomic/atomic/store/
  131. int test_atomic_store()
  132. {
  133. // atomic::store: Replaces the contained value with val.
  134. // The operation is atomic and follows the memory ordering specified by sync.
  135. std::thread first(print_foo);
  136. std::thread second(set_foo, 10);
  137. first.join();
  138. second.join();
  139. return 0;
  140. }
  141. /
  142. // reference: http://www.cplusplus.com/reference/atomic/atomic_flag/clear/
  143. std::atomic_flag lock_stream = ATOMIC_FLAG_INIT;
  144. std::stringstream stream;
  145. void append_number(int x)
  146. {
  147. while (lock_stream.test_and_set()) {}
  148. stream << "thread #" << x << '\n';
  149. lock_stream.clear();
  150. }
  151. int test_atomic_flag_atomic_clear()
  152. {
  153. // atomic_flag::clear: Clears the atomic_flag (i.e., sets it to false)
  154. //Clearing the atomic_flag makes the next call to member atomic_flag::test_and_set on this object return false.
  155. // The operation is atomic and follows the memory ordering specified by sync.
  156. // atomic_flag::test_and_set: Sets the atomic_flag and returns whether it was already set immediately before the call
  157. // The entire operation is atomic (an atomic read-modify-write operation): the value is not affected by other threads
  158. // between the instant its value is read (to be returned) and the moment it is modified by this function.
  159. std::vector<std::thread> threads;
  160. for (int i = 1; i <= 10; ++i) threads.push_back(std::thread(append_number, i));
  161. for (auto& th : threads) th.join();
  162. std::cout << stream.str();
  163. return 0;
  164. }
  165. } // namespace atomic

GitHub: https://github.com/fengbingchun/Messy_Test

转载自:https://blog.csdn.net/fengbingchun/article/details/73436710

Multi-thread--C++11中atomic的使用相关推荐

  1. C++11中头文件atomic的使用

    原子库为细粒度的原子操作提供组件,允许无锁并发编程.涉及同一对象的每个原子操作,相对于任何其他原子操作是不可分的.原子对象不具有数据竞争(data race).原子类型对象的主要特点就是从不同线程访问 ...

  2. C++11中头文件thread的使用

    C++11中加入了<thread>头文件,此头文件主要声明了std::thread线程类.C++11的标准类std::thread对线程进行了封装.std::thread代表了一个线程对象 ...

  3. Multi-thread--C++11中thread的使用

    C++11中加入了<thread>头文件,此头文件主要声明了std::thread线程类.C++11的标准类std::thread对线程进行了封装.std::thread代表了一个线程对象 ...

  4. C++11中Thread类简单使用的例子

    代码如下: #include <iostream> #include <thread> #include <chrono> #include <future& ...

  5. c++11中thread join和detach的区别

    线程状态: 在一个线程的生存期内,可以在多种状态之间转换,不同的操作系统可以实现不同的线程模型,定义许多不同的线程状态,每个状态还可以包含多个子状态,但大体来说,如下几种状态是通用的: 1)就绪:参与 ...

  6. C++11中std::future的使用

    C++11中的std::future是一个模板类.std::future提供了一种用于访问异步操作结果的机制.std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::sha ...

  7. Visual C++ 11 中新的并发功能

    最新的 C++ 迭代(称为 C++11,在去年通过了国际标准化组织 (ISO) 的审批)形式化了一组新库和一些保留字以处理并发. 许多开发者以前都在 C++ 中使用过并发功能,但都是通过第三方的库,即 ...

  8. C++11中std::async的使用

    C++11中的std::async是个模板函数.std::async异步调用函数,在某个时候以Args作为参数(可变长参数)调用Fn,无需等待Fn执行完成就可返回,返回结果是个std::future对 ...

  9. C++11中std::packaged_task的使用

    C++11中的std::packaged_task是个模板类.std::packaged_task包装任何可调用目标(函数.lambda表达式.bind表达式.函数对象)以便它可以被异步调用.它的返回 ...

最新文章

  1. Aggregation,Composition和Dependency
  2. docker 安装iproute包 包含 ss ip 命令
  3. 华为FusionCloud 云计算解决方案及相关资料下载
  4. 二进制八进制十六进制之间的快速转换------ 心算笔算方法总结
  5. 纯原生仿ES6的Object.assign,实现深度合并对象
  6. 【汇编语言】王爽实验5(5)(6)的解答 建立数据类型匹配的观念
  7. 跟我一起屏蔽百度搜索页面右侧的内容
  8. mysql跟memcache的区别_MySQL-mysql Memory Storage Engine 和memcache到底有何不同?各自的优缺点是什么?...
  9. Java复习总结(一)思维导图
  10. PCL Lesson1 :PCL库PCLVisualizer的简单使用
  11. Java注解的作用?
  12. 关于Julia 和Matlab速度的比较!(以偏概全)。
  13. 怎么把word转换ppt?
  14. qq批量提取群成员_学会这个QQ营销技巧,助你一天引流200+
  15. 计算机接口接触不良,如何处理电脑耳机插口接触不良
  16. 基于QT实现的计算器(只需要简单的栈知识,不仅仅是四则运算,接近手机内置计算器功能)
  17. selenium录屏python_Selenium实现录屏的一种方法
  18. ACurveTracer软件-可兼容多种仪器的测量软件
  19. (基础)选择器的语法
  20. 终极方法--解决Tomcat启动闪退

热门文章

  1. Vue-cli3配置教程入门
  2. 使用Docker-Compose安装GitLab服务器
  3. java UDP 使用示例
  4. LeetCode 678 有效的括号字符串,常规栈思路
  5. 【Python爬虫】Scrapy爬虫框架
  6. 【Python爬虫】一个简单的网络爬虫
  7. python解析格式文件
  8. 从头算和密度泛函理论_PHP Laravel教程–如何从头开始构建关键字密度工具
  9. javascript教程_JavaScript教程
  10. python对英语的要求_英语和数学都不好,但是我想学Python编程可以吗?