当前位置: 首页 > news >正文

多线程编程中什么时候使用锁和原子操作

在高并发编程中,锁(std::mutex原子操作(std::atomic 都可以用来保证线程安全,但它们的适用场景不同。选择哪种方式取决于性能、代码复杂度以及对数据一致性的要求。


1. 适用于 std::atomic(无锁编程)的场景

1.1 适用于简单数据类型的并发修改

如果你需要在多个线程间修改简单的数据类型(如 intbool、指针等),并且这些操作可以用单个 CPU 原子指令完成,则 std::atomic 更合适。

适用场景

  • 计数器(如请求数、访问次数)
  • 标志位(如任务完成标志 std::atomic<bool>
  • 指针交换(如 std::atomic<void*> 共享数据指针)

示例:线程安全的计数器

std::atomic<int> counter{0};

void worker() {
    for (int i = 0; i < 1000; ++i) {
        counter.fetch_add(1, std::memory_order_relaxed);
    }
}
  • fetch_add() 直接使用 CPU 无锁指令,多个线程可以同时执行,无需等待。

1.2 适用于无锁数据结构

如果你在实现 高性能数据结构,如无锁队列(lock-free queue)或无锁栈(lock-free stack),std::atomic 是必要的。

适用场景

  • 无锁队列(Lock-Free Queue)
  • 无锁栈(Lock-Free Stack)
  • 无锁哈希表(Lock-Free HashMap)

示例:无锁栈(Lock-Free Stack)

struct Node {
    int data;
    Node* next;
};

std::atomic<Node*> head{nullptr};

void push(int value) {
    Node* new_node = new Node{value, nullptr};
    do {
        new_node->next = head.load();
    } while (!head.compare_exchange_weak(new_node->next, new_node));
}
  • compare_exchange_weak() 确保 head 在修改前仍然是预期值,如果 head 被其他线程改了,会自动重试。

1.3 适用于低延迟场景

高性能计算实时系统中,std::atomic 能减少线程同步的开销,避免上下文切换

适用场景

  • 实时系统(如音视频处理)
  • 游戏引擎(如帧率控制、输入处理)
  • 高频金融交易(如撮合交易引擎)

示例:多线程计时器

std::atomic<bool> stop_timer{false};

void timer() {
    while (!stop_timer.load()) {
        // 执行定时任务
    }
}
  • std::atomic<bool> 可以被多个线程安全地访问,不会产生锁竞争。

2. 适用于 std::mutex(锁)的场景

尽管原子操作效率更高,但在以下情况下,std::mutex 更适合


2.1 适用于修改复杂数据结构

如果数据结构较复杂,且多个线程需要同时修改多个变量,那么 std::mutex 更安全。

适用场景

  • 修改 std::vectorstd::map 等 STL 容器
  • 修改多个变量
  • 涉及条件变量(std::condition_variable)的情况

不适合用 std::atomic 的例子

struct Data {
    int x;
    int y;
};
std::atomic<Data> data;  // ❌ 错误,不能直接用 std::atomic 处理多个变量

上面代码是错误的,因为 std::atomic 不能保证 xy 在一起更新的原子性。

正确做法:使用 std::mutex

struct Data {
    int x;
    int y;
};
Data data;
std::mutex data_mutex;

void update() {
    std::lock_guard<std::mutex> lock(data_mutex);
    data.x += 1;
    data.y += 1;
}
  • std::mutex 确保 xy 同时更新,防止竞争条件(race condition)。

2.2 适用于写多读少(写多线程竞争激烈)

如果写操作频繁,std::atomic 可能导致**缓存一致性(cache coherence)**问题,而 std::mutex 可以降低竞争。

适用场景

  • 高频写入、低频读取的共享资源
  • 数据库事务
  • 日志系统

示例:日志系统

std::mutex log_mutex;

void log(const std::string& message) {
    std::lock_guard<std::mutex> lock(log_mutex);
    std::cout << message << std::endl;
}
  • std::mutex 确保多个线程不会交错输出日志。

2.3 适用于临界区需要长时间执行

如果代码逻辑较复杂,需要执行多个步骤,使用 std::atomic 不现实,此时 std::mutex 更合适。

适用场景

  • 需要执行多个步骤的临界区
  • 持有锁的时间较长

示例:银行账户

struct Account {
    int balance;
    std::mutex mtx;
};

void transfer(Account& from, Account& to, int amount) {
    std::lock_guard<std::mutex> lock(from.mtx);
    from.balance -= amount;
    
    std::lock_guard<std::mutex> lock2(to.mtx);
    to.balance += amount;
}
  • std::atomic 无法保证多个账户的一致性,必须用 std::mutex 保护。

3. 选择 std::atomic 还是 std::mutex

场景适合 std::atomic适合 std::mutex
共享简单变量(如 intbool
共享指针(如 std::atomic<void*>
复杂数据结构(如 std::vector
需要修改多个变量
高性能低延迟应用(如游戏引擎)
需要等待(如 std::condition_variable
数据库事务、日志系统
读多写少的场景
写多读少的场景

4. 结论

  • std::atomic 适用于无锁编程,适用于高性能、短时锁定的操作(计数器、标志位、指针交换)
  • std::mutex 适用于修改多个变量、复杂数据结构、需要等待的场景
  • 如果可以使用 std::atomic,优先使用 std::atomic,因为它避免了上下文切换,提高了性能
  • 但当 std::atomic 不能满足一致性需求时(如同时修改多个变量),必须使用 std::mutex

所以,在实际应用中,先尝试用 std::atomic,如果无法保证数据完整性,再考虑 std::mutex! 🚀

相关文章:

  • Leetcode 3495. Minimum Operations to Make Array Elements Zero
  • 《基于Flask的态势感知系统》开题报告
  • Edge浏览器如何默认启动某个工作区 / 为工作区添加快捷方式
  • 设置GeoJSONVectorTileLayer中的line填充图片
  • C++-C++中的几种cast
  • 大数据中的数据预处理:脏数据不清,算法徒劳!
  • Codeforces Round 1011 (Div. 2) CD
  • Spring AOP + RocketMQ 实现企业级操作日志异步采集(实战全流程)
  • linux 备份工具,常用的Linux备份工具及其备份数据的语法
  • Apache漏洞再现
  • 每日算法-250323
  • 常见中间件漏洞攻略-Weblogic篇
  • Jenkins最新版,配置Gitee私人令牌和Gitee凭证
  • 2025年中国AI搜索的行业洞察报告
  • 如何使用SystemVerilog SVA检查跨时钟域信号?
  • C++多线程编程:从创建到管理的终极指南
  • VLAN章节学习
  • 万象更新(一)VTK 坐标轴、相机方向坐标轴、立方体坐标轴
  • 基于 C++ 类的程序设计模式与应用研究
  • Python个人学习笔记(19):模块(正则表达式)
  • 东风着陆场做好各项搜救准备,迎接神舟十九号航天员天外归来
  • 广东雷州农商行董事长、原行长同日被查
  • 伊朗国防部发言人:发生爆炸的港口无进出口军用物资
  • “下山虎”张名扬一回合摘下“狮心”:你们再嘘一个给我听听
  • 海南高院通报去年知产领域司法保护状况:审结民事一审案件4847起
  • 公安部知识产权犯罪侦查局:侦破盗录传播春节档院线电影刑案25起