C++下的atomic | atmoic_flag | 内存顺序

什么是原子操作?

"原子操作" 是不可分割的操作------ 要么完整执行,要么完全不执行,中间不会被其他线程打断。

例如:普通 int count++ 是 "读→改→写" 三步,多线程下会出现数据竞争;而 std::atomic<int> count; count++ 是一步原子操作,线程安全。

底层原理

std::atomic 依赖硬件 + 软件实现线程安全:

  1. 硬件原子指令 :现代 CPU(x86/ARM)提供 CMPXCHG(CAS)、原子加减等指令,将 "读 - 改 - 写" 封装为一步不可分割的操作;
  2. 缓存一致性协议:如 MESI 协议,保证一个 CPU 修改原子变量后,其他 CPU 的缓存会同步更新;
  3. C++ 封装std::atomic 是硬件原子指令的 C++ 语法封装,无需写汇编即可使用。

std::atomic 类模板概述

std::atomic类模板 ,仅支持平凡可复制类型 (如 intdouble、指针),不支持 std::string 等复杂类型。

类模板简化声明:

复制代码
template <class T>
struct atomic {
    // 核心成员函数(下文详解)
};

常用特化:std::atomic<int>std::atomic<long>std::atomic<char*> 等。

1. 原子读:load()

  • 函数声明

    复制代码
    T load(std::memory_order order = std::memory_order_seq_cst) const noexcept;
  • 参数

    • order:内存顺序(默认 memory_order_seq_cst,最严格的全局一致顺序);
  • 作用:原子地读取原子变量的当前值,保证读到最新结果;

  • 返回值 :原子变量的当前值(类型为 T)。

2. 原子写:store()

  • 函数声明

    复制代码
    void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept;
  • 参数

    • desired:想要设置给原子变量的新值;
    • order:内存顺序(默认 memory_order_seq_cst);
  • 作用 :原子地将原子变量的值设为 desired,写操作不会被其他线程打断;

  • 返回值:无。

3. 原子加:fetch_add()

复制代码
T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
  • 参数
    • arg:要给原子变量增加的数值;
    • order:内存顺序(默认 memory_order_seq_cst);
  • 作用 :原子地将原子变量的值 arg,操作不可分割;
  • 返回值 :原子变量在 "加arg之前" 的旧值(类型为 T)。

4. 原子减:fetch_sub()

复制代码
T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
  • 参数
    • arg:要给原子变量减少的数值;
    • order:内存顺序(默认 memory_order_seq_cst);
  • 作用 :原子地将原子变量的值 arg,操作不可分割;
  • 返回值 :原子变量在 "减arg之前" 的旧值(类型为 T)。

5. compare_exchange_weak

复制代码
bool compare_exchange_weak(
    T& expected,
    T desired,
    std::memory_order success = std::memory_order_seq_cst,
    std::memory_order failure = std::memory_order_seq_cst
) noexcept;
  • 参数
    • expected引用类型,表示 "期望原子变量当前的值";
    • desired:若原子变量值等于 expected,要设置的新值;
    • success:CAS 成功时使用的内存顺序;
    • failure:CAS 失败时使用的内存顺序;
  • 作用
    1. 比较原子变量当前值与 expected
    2. 相等 :将原子变量设为 desired,返回 true
    3. 不相等 :将 expected 更新为原子变量的当前值,返回 false;(注:可能 "虚假失败",需配合 while 循环使用);
  • 返回值booltrue 表示 CAS 成功,false 表示失败。

6. compare_exchange_strong

复制代码
bool compare_exchange_strong(
    T& expected,
    T desired,
    std::memory_order success = std::memory_order_seq_cst,
    std::memory_order failure = std::memory_order_seq_cst
) noexcept;
  • 参数 :与 compare_exchange_weak 完全相同;
  • 作用 :与 compare_exchange_weak 逻辑一致,但不会虚假失败
  • 返回值booltrue 表示 CAS 成功,false 表示失败。

7. 自增 / 自减运算符(语法糖)

std::atomic<T> 重载了 ++/--,本质是 fetch_add(1)/fetch_sub(1) 的简化:

  • 前置自增:T& operator++() noexcept;(返回新值);
  • 后置自增:T operator++(int) noexcept;(返回旧值);
  • 前置自减:T& operator--() noexcept;(返回新值);
  • 后置自减:T operator--(int) noexcept;(返回旧值)。

特殊原子类型:std::atomic_flag

std::atomic_flag强制免锁的原子布尔类型(C++ 标准要求),仅用于实现自旋锁。

类简化声明:

复制代码
struct atomic_flag {
    // 核心成员函数
};

atomic_flag 核心成员函数

1. test_and_set()
  • 函数声明

    复制代码
    bool test_and_set(std::memory_order order = std::memory_order_seq_cst) noexcept;
  • 参数

    • order:内存顺序(默认 memory_order_seq_cst);
  • 作用 :原子地将 atomic_flag 设为 true

  • 返回值atomic_flag 在 "设为true之前" 的旧值(bool类型)。

2. clear()
  • 函数声明

    复制代码
    void clear(std::memory_order order = std::memory_order_seq_cst) noexcept;
  • 参数

    • order:内存顺序(默认 memory_order_seq_cst);
  • 作用 :原子地将 atomic_flag 设为 false

  • 返回值:无。


内存顺序(std::memory_order

std::atomic 函数的 order 参数控制内存同步行为,新手常用 3 种:

  1. memory_order_relaxed
    • 作用:仅保证原子性,无同步 / 顺序约束;
    • 适用场景:计数器等无需同步的场景。
  2. memory_order_acquire
    • 作用:当前操作前的读写不会被重排序到之后;
    • 适用场景:加载操作(配合 release 同步数据)。
  3. memory_order_release
    • 作用:当前操作后的读写不会被重排序到之前;
    • 适用场景:存储操作(配合 acquire 同步数据)。
  4. memory_order_seq_cst(默认)
    • 作用:全局顺序一致,所有线程看到的操作顺序相同;
    • 适用场景:需要强一致性的场景(性能略低)。

应用场景

线程安全计数器

fetch_add() 实现:

复制代码
#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
using namespace std;

atomic<int> atomic_cnt = 0; // 原子计数器

void add() {
    for (int i = 0; i < 10000; ++i) {
        // 原子加1,用relaxed内存顺序(更快)
        atomic_cnt.fetch_add(1, memory_order_relaxed);
    }
}

int main() {
    vector<thread> threads;
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back(add);
    }
    for (auto& t : threads) t.join();

    cout << "原子计数器结果:" << atomic_cnt.load() << endl; // 输出40000
    return 0;
}

atomic_flag 实现自旋锁

复制代码
#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
using namespace std;

class SpinLock {
private:
    atomic_flag flag = ATOMIC_FLAG_INIT; // 初始化为false
public:
    void lock() {
        // 循环直到拿到锁:test_and_set返回false表示成功
        while (flag.test_and_set(memory_order_acquire));
    }
    void unlock() {
        flag.clear(memory_order_release); // 释放锁
    }
};

SpinLock lock;
int shared_val = 0;

void worker() {
    lock.lock();
    for (int i = 0; i < 10000; ++i) {
        shared_val++;
    }
    lock.unlock();
}

int main() {
    vector<thread> threads;
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back(worker);
    }
    for (auto& t : threads) t.join();

    cout << "共享变量结果:" << shared_val << endl; // 输出40000
    return 0;
}

多线程头插链表

复制代码
#include<iostream>
#include<chrono>
#include<atomic>
#include<thread>
#include<vector>
using namespace std;
struct Node {
	int _val;
	Node* _next;
	Node(int val,Node*next):_val(val),_next(next){}
};
atomic<Node*>list;
void push_head(int val) {
	this_thread::sleep_for(chrono::seconds(1));
	Node* old_ = list.load();
	Node* new_=new Node( val, old_ );
	while (!list.compare_exchange_weak(old_, new_))
		new_->_next = old_;
}
int main() {
	vector<thread>vt;
	for (int i = 0; i < 5; i++) {
		vt.emplace_back(push_head,i);
	}
	for (auto& it : vt)it.join();
	Node* n = list.load();
	while (n) {
		cout << n->_val << " ";
		n = n->_next;
	}
}

atomic_flag vs atomic<bool>

维度 std::atomic_flag std::atomic<bool>
类声明 struct atomic_flag; template<> struct atomic<bool>;
免锁性 强制免锁(C++ 标准要求) 主流平台免锁,小众平台可能用锁模拟
核心函数 1. bool test_and_set(memory_order);2. void clear(memory_order); 1. bool load(memory_order);2. void store(bool, memory_order);3. bool compare_exchange_weak(...)
初始化 必须用 ATOMIC_FLAG_INIT(默认 false) 直接赋值(如 atomic<bool> f = true;
核心用途 实现自旋锁 通用原子布尔标记(开关、状态位)

weak vs strong 核心差异

维度 compare_exchange_weak compare_exchange_strong
核心特性 可能发生虚假失败(Spurious Failure) 无虚假失败,"相等则必成功"
虚假失败定义 即使原子变量值 == expected,也可能返回 false 只要原子变量值 == expected,一定返回 true
性能 更快(底层适配硬件指令,减少锁 / 重试逻辑) 略慢(需额外逻辑避免虚假失败)
相关推荐
木叶子---2 小时前
pdf生成排查记录与解决方案
java·pdf
Sylvia-girl2 小时前
Java之异常
java·开发语言
郝学胜-神的一滴2 小时前
Python对象的自省机制:深入探索对象的内心世界
开发语言·python·程序人生·算法
Sylvia33.2 小时前
网球/羽毛球数据API:专业赛事数据服务的技术实现
java·前端·websocket·json
说私域2 小时前
全民电商时代下的链动2+1模式与S2B2C商城小程序:社交裂变与供应链协同的营销革命
开发语言·人工智能·小程序·php·流量运营
爱丽_2 小时前
Spring 框架
java·后端·spring
跃渊Yuey2 小时前
【Linux】Linux进程信号产生和保存
linux·c语言·c++·vscode
期待のcode2 小时前
浅堆深堆与支配树
java·jvm·算法
小北方城市网2 小时前
SpringBoot 集成 RabbitMQ 实战(消息队列):实现异步通信与系统解耦
java·spring boot·后端·spring·rabbitmq·mybatis·java-rabbitmq