C++11 在 <atomic> 头文件中引入了 atomic 模板,对原子对象进行了封装。我们可以将其应用到任何类型上去。当然对于不同的类型效果还是有所不同的:对于整型量和指针等简单类型,通常结果是无锁的原子对象;而对于另外一些类型,比如 64 位机器上大小不是 1、2、4、8(有些平台 / 编译器也支持对更大的数据进行无锁原子操作)的类型,编译器会自动为这些原子对象的操作加上锁。编译器提供了一个原子对象的成员函数 is_lock_free,可以检查这个原子对象上的操作是否是无锁的。
原子操作有三类:读:在读取的过程中,读取位置的内容不会发生任何变动。写:在写入的过程中,其他执行线程不会看到部分写入的结果。读‐修改‐写:读取内存、修改数值、然后写回内存,整个操作的过程中间不会有其他写入操作插入,其他执行线程不会看到部分写入的结果。
<atomic> 头文件中还定义了内存序,分别是:
- memory_order_relaxed:松散内存序,只用来保证对原子对象的操作是原子的memory_order_consume:目前不鼓励使用,我就不说明了
- memory_order_acquire:获得操作,在读取某原子对象时,当前线程的任何后面的读写操作都不允许重排到这个操作的前面去,并且其他线程在对同一个原子对象释放之前的所有内存写入都在当前线程可见
- memory_order_release:释放操作,在写入某原子对象时,当前线程的任何前面的读写操作都不允许重排到这个操作的后面去,并且当前线程的所有内存写入都在对同一个原子对象进行获取的其他线程可见
- memory_order_acq_rel:获得释放操作,一个读‐修改‐写操作同时具有获得语义和释放语义,即它前后的任何读写操作都不允许重排,并且其他线程在对同一个原子对象释放之前的所有内存写入都在当前线程可见,当前线程的所有内存写入都在对同一个原子对象进行获取的其他线程可见
- memory_order_seq_cst:顺序一致性语义,对于读操作相当于获取,对于写操作相当于释放,对于读‐修改‐写操作相当于获得释放,是所有原子操作的默认内存序(除此之外,顺序一致性还保证了多个原子量的修改在所有线程里观察到的修改顺序都相同;我们目前的讨论暂不涉及多个原子量的修改)