C++11中增加的官方并发支持库包含了名为<atomic>的头文件,此文件中定义了原子变量std::atomic<T>,及其各种类型特化别名atomic_bool,atomic_char等。
“原子”指的是一系列不可分割的操作或单元,它们组合在一起形成了原子操作(Atomic Operation)。这意味着在执行原子操作时,它要么完全成功,要么完全失败,没有中间状态,保证了操作的完整性。原子拥有的原子性确保了在并发编程中数据的一致性和可靠性。、
std::atomic
摘录于std::atomic - cppreference.com
类定义
定义于头文件<atomic> template < class T >
struct atomic ;(since C++11)
构造函数重载operator=,不允许类外使用 = 进行对象间拷贝
atomic ( ) noexcept = default ;默认无参构造 constexpr atomic ( T desired ) noexcept ;使用desired初始化原子变量 atomic ( const atomic & ) = delete ;显式删除拷贝构造,不允许对象间拷贝 以原子方式将当前值替换为 desired ,根据 order 的值影响内存访问顺序。(默认为5)
T operator=( T desired ) noexcept;
T operator=( T desired ) volatile noexcept;
atomic& operator=( const atomic& ) = delete;
atomic& operator=( const atomic& ) volatile = delete;
以原子方式加载并返回原子变量的当前值,根据order的值影响内存访问顺序。
void store( T desired, std::memory_order order = std::memory_order_seq_cst ) noexcept;
void store( T desired, std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;
内存顺序
T load( std::memory_order order = std::memory_order_seq_cst) const noexcept;
T load( std::memory_order order = std::memory_order_seq_cst ) const volatile noexcept;
typedef enum 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 } memory_order;
检查此类型的所有对象的原子操作是否无锁,若是返回true,否则返回false静态成员常量,检查类型 T 是否总是无锁操作
bool is_lock_free() const noexcept;
(since C++11) bool is_lock_free() const volatile noexcept;
(since C++11)
static constexpr bool is_always_lock_free = /*implementation-defined*/;
(since C++17)
C++20新增了新的成员函数:
//wait函数:
void wait(T old,std::memory_order order = std::memory_order_seq_cst)const noexcept;
void wait(T old,std::memory_order order = std::memory_order_seq_cst)const volatile noexcept;
-------------------------------------------------------------------
//notify_one函数:
void notify_one() noexcept;
void notify_one() volatile noexcept;
-------------------------------------------------------------------
//notify_all函数:
void notify_all() noexcept;
void notify_all() volatile noexcept;
可以通过原子类型 阻塞 / 唤醒 线程,与条件变量中的函数一样。
原子操作相比锁的优势
1. 细粒度控制:
原子操作允许对共享数据的更细粒度控制。可以针对单个变量或数据结构的特定部分执行原子操作,而不是锁住整个数据结构或临界区。这可以减小竞争的范围,提高并发性能。
2. 低开销:
原子操作通常比锁的开销更低。锁需要进行线程的上下文切换、调度和内核态与用户态之间的切换,而原子操作通常是在用户态执行的,避免了这些开销。
3. 避免死锁:
锁可能导致死锁情况,其中多个线程互相等待对方释放锁资源。原子操作不会导致死锁,因为它们是无阻塞的。
4. 适用于特定问题:
原子操作通常更适用于一些特定的问题,如计数器更新、标志位的设置或清除等简单操作。这些操作可以轻松地使用原子指令来实现,而不需要引入锁的复杂性。
5. 更容易实现和维护:
使用原子操作的代码通常更容易实现和维护,因为无需担心锁的获取和释放、死锁、优化和调优等问题。使代码更简洁且易于理解。
当然,并发问题多种多样,在复杂的同步问题上,锁的灵活性可能会更有优势,根据问题的不同看情况选择合适的方法。