背景:
在复杂场景中,比如共享数据结构链表,map,等需要多步操作,需要用到互斥锁来保护,而对于简单场景,比如只是一条简单的赋值,加减操作,则加锁解锁显得笨重,也影响性能。因此,c++11引入 std::atomic工具。
基本:
是一个类模板,
1.基本数据类型
std::atomic<char> ac('H');
std::atomic<bool> ai(0);
2.指针类型
std::atomic<char*> ap1(nullptr);
std::atomic<void*> ap2(ullptr);
3.自定义类型
struct Demo {
Demo();
int a;
int b;
};
std::atomic<Demo> ao;
对于自定义类型,类中不能包含以下成员,否则无法作为std::atomic模板参数。
a.拷贝构造函数,拷贝赋值,移动构造,移动赋值,西构函数
b.虚函数
c.包含引用成员
必须支持平凡拷贝(即可以通过memcpy正确拷贝)(简单拷贝)
操作方法:
std::atomic<int> ai(0);
1.读取值
int v = ai.load(); //注意ai.load()是原子操作,不会被打断,但是赋值到v是非原子性的
2.设置值
ai.store(10);
ai = 10;
std::cout << "v=" << ai << "\n";//注意:这里atomic并没有重载<<运算符,。这里是将ai转换了int,在cout输出
3.读取旧值,并设置新值,返回旧值
int old_v = ai.exchange(20);
4.不同类型支持原子操作不同
a.对于int 类型,
ai += 10; 等价于 ai.fetch_add(10);
ai &= 10; 等价于 ai.fetch_and(10;
ai++;
b.对于指针类型
std::atomic<int*> ap(nullptr);
ap++;
ap+=2;
ap.fetch_add(2)
c.对于double类型的原子变量,不支持上述操作
...
CAS操作:
Compare-And-Swap,多线程编程里的原子操作,用来实现无锁同步.
原子的执行:
如果 原子变量的当前值== 预期值(expected)
则把原子变量更新为新值(desired),并返回true
否则
把原子变量当前值写回到 expected,返回false
API:
bool compare_exchange_strong(T& expected, T desired);
bool compare_exchange_weak(T& expected,T desired);
strong和weak逻辑一样,但区别在于:weak可能因为硬件或优化原因返回false,出现虚假失败
memory_order:内存顺序
- memory_order_relaxed:当前线程里,编译器和cpu可以随便重排这条原子操作的前后指令
- memory_order_release:保证这条原子下之前的所有普通读写操作,都不能重排到它后面
- memory_order_acquire:保证这条原子读之后的所有普通读写操作,都不能被重排到它前面
- memory_order_acq_rel:既阻止前面的操作被重排到后面,也阻止后面的操作被重排到前面