std::atomic_flag是最简单的标准原子类型,它表示了一个bool标志。这个类型的对象可以在两个状态切换:设置和清除。
std::atomic_flag类型的对象必须被ATOMIC_FLAG_INIT初始化,初始化标志位是清除状态。
1 | std::atomic_flag f = ATOMIC_FLAG_INIT; |
这适用于任何对象的声明,并且可以在任意范围内。它是唯一需要以这种方式初始化的原子类型,它是唯一保证无锁的类型。std::atomic_flag在首次使用时,都需要初始化。当std::atomic_flag对象已经初始化,那么对于此对象只能做三件事情:销毁,清除或设置。这些操作对应的函数分别是: clear()成员函数,和test_and_set()成员函数。
clear()和test_and_set()成员函数可以指定内存顺序。clear()是一个存储操作,所以不能有memory_order_acquire或memory_order_acq_rel语义。但是test_and_set()是一个读-改-写操作,所有可以应用于任何内存顺序标签。每一个原子操作,默认的内存顺序都是memroy_order_seq_cst。例如:
1 | f.clear(std::memory_order_release); |
对于std::atomic_flag对象不能进行拷贝构造,也不能将一个对象赋予另一个std::atomic_flag对象。copy constructor和copy assignment 都是不支持的,对于所有的原子类型而言。因为赋值和拷贝构造都会包含操作的原子性。下面使用std::atomic_flag实现一个自选互斥锁。初始化标志是“清除”,并且互斥量处于解锁状态。为了锁上互斥量,循环运行test_and_set()直到旧值为false,就意味着这个线程已经被设置为true了。解锁互斥量是一件很简单的事情,将标志清除即可:
1 | class Spinlock_mutex{ |
使用std::atomic_flag的示例如下:
1 |
|
下表是一个内存顺序模型和值:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |