C++高性能无锁并发编程
前置铺垫
指令重排
指令重排是指编译器或CPU为了优化程序的执行性能而对指令进行重新排序的一种手段。
在非并发情景下他并不会改变最终执行结果,但会更改执行过程顺序。
但在并发情景下,指令重排会引发意想不到的错误。
我们在编程时,编写的代码是这样的。
int main() { |
但编译后则可能会出现以下顺序
int main() { |
重排前后的最终结果a = b = 1,c = d = 2。
指令重排遵循顺序执行原则,保证单线程内语义的串行性,即不管怎么进行指令重排序,单线程内程序的执行结果不能被改变。
内存屏障
在并发编程中,我们希望在部分代码段禁用指令重排。
加入内存屏障的代码段将禁用指令重排。
更为严格的描述:重排后的指令不可能插入至有内存屏障的代码段。
内存顺序
位于
<atomic>
标头内。
在C++中封装了以下内存顺序。
enum class memory_order : int |
原子操作默认使用
std::memory_order::seq_cst
。
std::memory_order::relaxed
- 只保证原子操作,不保证指令顺序。
// no barrier |
std::memory_order::consume
- 有此内存序的加载操作,在其影响的内存位置进行消费操作。
- 当前线程中依赖于当前加载的值的读或写不能被重排到此加载之前。其他线程中对有数据依赖的变量进行的释放同一原子变量的写入,能为当前线程所见。在大多数平台上,这只影响到编译器优化。
std::memory_order::acquire
- 用于获取(load)原子变量值相关的操作。
- 对于使用memory_order_acquire内存顺序的指令,该指令后面的所有读写操作不能重排在该指令之前。
- 当前线程执行的memory_order_acquire指令能够保证读到其他线程memory_order_release指令之前的所有内存写入操作。
// barrier ^ |
std::memory_order::release
- 用于设置(store)原子变量值相关的操作。
- 对于使用memory_order_release内存顺序的指令,该指令之前的所有读写操作不能重排在该指令之后。
- 当前线程memory_order_release指令之前的所有内存写操作对于其他线程memory_order_acquire指令之后可见。
expression with std::memory_order::release; |
std::memory_order::_seq_cst
// barrier ^ |
释放-获取定序(Acquire-Release)
无锁队列
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 whaleghostの小窝!