atomic用法
memory order
源码变成可执行程序,一般由预编译,编译,汇编,链接。源码重排序一般分为编译期重排序和运行期重排序。
编译期重排序:编译器在不改变单线程程序的语义的前提下,可以重新安排语句的执行顺序。在不改变程序的语义的前提下,尽可能减少寄存器的读取,存储次数,充分复用寄存器的存储值。
CPU乱序执行
名称 | 语义 |
memory_order_relaxed | Relaxed语义 |
memory_order_consume | Release-Acquire语义 |
memory_order_acquire | Release-Acquire语义 |
memory_order_release | Release-Acquire语义 |
memory_order_acq_rel | Release-Acquire语义 |
memory_order_seq_cst | Sequential consistency语义 |
synchronizes-with、happens-before关系
synchronizes-with: 如果线程A存储一个值,而线程B读取该值,那么线程A中的存储和线程B的载入之间存在一种synchronizes-with关系
happens-before: 如果一个操作排在另外一个操作之前,那么该操作就该发生于另一个操作之前
Relaxed语义
最宽松的内存操作约定,不会保证修改会不会及时被其他的线程看到,也不对乱序做任何要求
relaxed的原子类型操作不参与synchronizes-with关系。
不同变量的relaxed可以被自由的重排,前提它们服从所有约束下的happens-before关系
#include <atomic>
#include <thread>
#include <assert.h> atomic<bool> x, y;
atomic<int> z; void write_x_then_y()
{
x.store(true, memory_order_relaxed);
y.store(true, memory_order_relaxed);
} void read_y_then_x()
{
while (!y.load(memory_order_relaxed));
if (x.load(memory_order_relaxed))
++z;
}int main()
{
x = false;
y = false;
z = ;
thread a(write_x_then_y);
thread b(read_y_then_x);
a.join();
b.join();
assert(z.load() != ); // z可能等于0
}
Release-Acquire语义Sequential consistency语义
release和acquire总是一起使用
release用于写操作,acquire用于读操作
release之前的写操作不允许乱序到release之后, acquire之前的读操作不允许乱序到acquire之前
acquire的修改会及时被release看到
Sequential consistency语义
sequential consistency 相当于 release + acquire 之外,还加上了一个对该操作加上全局顺序的要求
#include <atomic>
#include <thread>
#include <assert.h> atomic<bool> x, y;
atomic<int> z; void write_x()
{
x.store(true, memory_order_seq_cst);
} void write_y()
{
y.store(true, memory_order_seq_cst);
} void read_x_then_y()
{
while (!x.load(memory_order_seq_cst));
if (y.load(memory_order_seq_cst))
++z;
} void read_y_then_x()
{
while(!y.load(memory_order_seq_cst));
if (x.load(memory_order_seq_cst))
++z;
} int main()
{
x = false;
y = false;
z = ;
thread a(write_x);
thread b(write_y);
thread c(read_x_then_y);
thread d(read_y_then_x);
a.join();
b.join();
c.join();
d.join();
assert(z.load() != ); // z不可能等于0
}
store,load
atomic<bool> x, y;
atomic<int> z; void write()
{
x.store(true, memory_order_relaxed);
y.store(true, memory_order_release); // x的值比y先填充值
} void read()
{
while(!y.load(memory_order_acquire)); // y在等write值得填充
if (x.load(memory_order_relaxed)) {
z++;
}
} int main()
{
x = false;
y = false;
z = ; thread t1(write);
thread t2(read);
t1.join();
t2.join(); cout << "z: " << z << endl;
}
exchage
compare_exchange_weak
bool compare_exchange_weak(T& expected, T val, memory_order sync = memory_order_seq_cst)
NOTE:
1. atomic变量的值与expected进行比较, 如果结果true, 用val更新atomic的值(like store); 如果结果为false, 用atomic的值更新expected的值.
2. 这个函数能获得这个atomic变量的值,并且如果比较的结果是true的话就修改这个值. 整个操作是原子操作,在读取或者修改这个值得瞬间,其他的线程不会修改这个值.
3. memory_order 是否生效也是根据比较的结果,如果结果为true,那么生效,否则不生效
4. compare_exchage_weak允许伪失败(fail spuriously),尽管expected值确实和atomic变量的值相等,仍然会返回false; 这需要使用while操作
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
using namespace std; struct Node {
int value;
Node *next;
}; atomic<Node*> list_head(nullptr);
void Append(int val)
{
Node *p_old_node = list_head;
Node *p_new_node = new Node {val, p_old_node}; while (!list_head.compare_exchange_weak(p_old_node, p_new_node)) {
p_new_node->next = p_old_node;
}
} int main()
{
vector<thread> threads;
for (int i = ; i < ; i++) {
threads.push_back(thread(Append, i));
} for (auto &i : threads) {
i.join();
} for (Node *it = list_head; it != nullptr; it = it->next) {
cout << it->value << " ";
}
cout << endl;
}
compare_exchange_strong
bool compare_exchange_strong (T& expected, T val, memory_order sync = memory_order_seq_cst)
1. compare_exchange_strong的用法和compare_exchange_weak基本用法都一样
2. compare_exchange_strong不允许伪失败(fail spuriously)
3. compare_exchange_weak的循环结构在某些机器上可能有更好的性能
atomic<int> ai;
int tst_val = ;
int new_val = ;
bool exchanged = false; void valsout()
{
cout << "ai: " << ai << " tst_val: " << tst_val << " new_val: " << new_val << " exchanged: " << boolalpha << exchanged << endl;
} int main()
{
ai = ;
valsout(); //ai = 3, tst_val = 4, new_val = 5, exchanged = false; exchanged = ai.compare_exchange_strong(tst_val, new_val);
valsout(); //ai = 3, tst_val = 3, new_val = 5, exchanged = false; exchanged = ai.compare_exchange_strong(tst_val, new_val);
valsout(); //ai = 3, tst_val = 3, new_val = 5, exchanged = false;
}
参考资料:
[1] http://www.cplusplus.com/reference/atomic/atomic/
[2] <<c++并发编程>>
[3] http://www.cnblogs.com/haippy/p/3252056.html
[4] http://www.cnblogs.com/muhe221/articles/5049474.html
最新文章
- 嵌入式系统添加无线wifi模块
- rabbitmq安装
- struts2总结二:第一个简单的struts2程序
- JQ中 trigger()和triggerHandler()区别
- 【转】HBase 超详细介绍
- TI CC2541的串口输出.
- DataGridView复选框实现单选功能(二)
- lintcode:等价二叉树
- C# DataGridView 导出 Excel(根据Excel版本显示选择不同后缀格式xls或xlsx)
- WindowState注意事项
- jq模拟操作
- Java内存管理思维导图
- JAVA容器结构图
- 安卓高级5 zXing
- 做自己的软件的Gallery(一)
- Java读取excel表,getPhysicalNumberOfCells()和getLastCellNum区别
- 2017(2)数据库设计,数据库设计过程,ER模型,规范化理论
- VUE框架的初识
- java基础学习总结——equals方法
- [转帖]全国产 台式机/笔记本/服务器都有 方正龙芯3A3000整机三连发