1. 引言

在多线程编程中,保护共享变量的并发安全是核心问题。对于简单变量(如整数、布尔值、指针等),开发者通常有两种选择:使用原子操作(std::atomic)或互斥锁(std::mutex)。两者都能保证数据一致性,但在性能、使用方式、适用场景上存在显著差异。本文将从多个维度对比二者的区别,帮助你在实际开发中做出合理选择。

2. 基本概念

2.1 什么是 Atomic(原子操作)

原子操作是指不可分割的操作,即该操作要么完整执行,要么完全不执行,不会出现中间状态。std::atomic 是 C++11 引入的模板类,它利用 CPU 提供的原子指令(如 LOCK 前缀指令)直接对内存进行操作,无需操作系统介入。

#include <atomic>

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

// 原子自增
counter.fetch_add(1);

2.2 什么是 Mutex(互斥锁)

互斥锁是一种同步原语,通过加锁(lock)和解锁(unlock)来保护临界区。同一时刻只允许一个线程持有锁,其他线程必须等待。std::mutex 是 C++11 提供的标准互斥锁实现。

#include <mutex>

int counter = 0;
std::mutex mtx;

// 加锁保护
{
    std::lock_guard<std::mutex> lock(mtx);
    ++counter;
}

3. 核心差异对比

3.1 性能差异

维度AtomicMutex
开销来源CPU 原子指令,无系统调用可能涉及系统调用与线程阻塞/唤醒
无竞争时极快,仅几条指令较快,但仍有锁获取/释放开销
高竞争时可能自旋等待,占用 CPU线程可能休眠,让出 CPU
适用规模轻量级高频操作重量级低频操作

结论:在低竞争场景下,atomic 通常比 mutex 快一个数量级以上;但在高竞争场景下,atomic 的自旋等待可能造成 CPU 空转,此时 mutex 的线程休眠机制反而更优。

3.2 功能差异

能力AtomicMutex
保护单个变量✅ 直接支持✅ 支持
保护多个变量/复杂逻辑❌ 不支持✅ 支持
读改写复合操作✅ 提供 fetch_addcompare_exchange✅ 需手动加锁
条件等待❌ 不支持✅ 配合 condition_variable
内存序控制✅ 可指定 memory_order❌ 不可控(默认全序)

3.3 使用复杂度

  • Atomic:API 简洁,无需管理锁的生命周期,不存在死锁风险。
  • Mutex:需要小心处理加锁/解锁配对,容易因异常或忘记解锁导致死锁;但 RAII 封装(如 lock_guard)可降低风险。

4. 典型场景示例

4.1 计数器累加

// Atomic 方式
std::atomic<int> count{0};
void increment() {
    count.fetch_add(1, std::memory_order_relaxed);
}

// Mutex 方式
int count = 0;
std::mutex mtx;
void increment() {
    std::lock_guard<std::mutex> lock(mtx);
    ++count;
}

4.2 共享标志位

// Atomic 方式
std::atomic<bool> ready{false};
// 线程 A
ready.store(true);
// 线程 B
if (ready.load()) { /* 执行 */ }

// Mutex 方式
bool ready = false;
std::mutex mtx;
// 线程 A
{
    std::lock_guard<std::mutex> lock(mtx);
    ready = true;
}
// 线程 B
{
    std::lock_guard<std::mutex> lock(mtx);
    if (ready) { /* 执行 */ }
}

5. 选择建议

场景推荐方案
单个简单变量的高频读写std::atomic
多个变量需要保持一致状态std::mutex
需要条件变量等待通知std::mutex + condition_variable
需要自定义内存序优化std::atomic
临界区包含复杂逻辑或 I/Ostd::mutex

6. 总结

atomicmutex 都能保证简单变量的线程安全,但设计哲学不同:atomic 通过硬件指令实现无锁的细粒度保护,适合高频、轻量的单变量操作;mutex 通过锁机制提供粗粒度的临界区保护,适合多变量、复杂逻辑或需要阻塞等待的场景。实际开发中应根据竞争程度、操作复杂度和性能要求综合权衡,必要时可混合使用两者。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐