C++多线程之原子操作 std::atomic
std::atomic 介绍
std::atomic 是 C++11 引入的模板类,用于支持多线程环境下的原子操作。原子操作是不可分割的操作,即在执行过程中不会被其他线程打断,从而避免数据竞争和未定义行为。
原子操作的概念
原子操作是指一个操作要么完全执行,要么完全不执行,不会出现部分执行的状态。在多线程环境中,原子操作能够确保对共享变量的读写是线程安全的,无需额外的锁机制。
适用场景
- 计数器或标志位的无锁更新
- 实现简单的同步机制(如自旋锁)
- 高性能并发场景,避免锁的开销
即atomic仅能处理 “单个变量的原子读写 / 交换 / 累加”(如计数器、标志位),一旦逻辑超过 “单个变量操作”,atomic就无能为力。atomic的核心价值就是无锁、高性能的单一变量同步
常用接口
std::atomic 提供以下常用成员函数:
load():原子读取变量的值store(val):原子写入变量的值exchange(val):原子交换变量的值并返回旧值compare_exchange_weak(expected, desired):比较并交换(弱版本)compare_exchange_strong(expected, desired):比较并交换(强版本)
经典应用场景
1.std::atomic用来做线程退出的标志位
//设置线程退出标志位
std::atomic <bool> m_flag;
//假设有一个工作线程
void work(){
while(!m_flag.load(std::memory_order_acquire))
{
std::cout<<"this thread is working..."<<std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main()
{
std::thread t(work);
std::this_thread::sleep_for(std::chrono::seconds(1));
//更改线程标志位
m_flag.store(true,std::memory_release) //std::memory_release规定写入权限对于线程可见
t.join();
return 0;
}
2.使用 std::atomic_flag 实现自旋锁
std::atomic_flag 是最简单的原子布尔类型,适合实现自旋锁
#include <atomic>
#include <thread>
class SpinLock {
public:
SpinLock() : flag(ATOMIC_FLAG_INIT) {}
void lock() {
while (flag.test_and_set(std::memory_order_acquire)) {
// 核心条件2: 满足自旋等待,不阻塞
}
}
void unlock() {
flag.clear(std::memory_order_release);
}
private:
std::atomic_flag flag; //核心条件1:原子操作
};
// 使用示例
SpinLock spinLock;
int sharedData = 0;
void increment() {
spinLock.lock();
++sharedData;
spinLock.unlock();
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
return 0;
}
1.std::atomic_flag是一个原子布尔开关,其只有std::atomic_flag::test_and_set()和std::atomic_flag::clear()两个接口。
2.std::atomic::test_and_set(): 有两个返回值:1.false-表示当前锁未被占用
2.true-表示当前锁已被占用
返回的是旧值(即标志位被更改之前的值)。其核心逻辑是原子性的完成(测试标志位状态+设置标志位为置位)两个动作,其动作不可被线程调度打断,要么完成,要么不进行。
可能有的读者会误认为,test_and_set()是先测试锁是否被占用,没有被占用再获取锁,并将其标志位改为置用。 但其实并不是这样,其操作逻辑是先获取标志位状态,并且不管当前锁有没有没占用,都将标志位改为占用,再返回获取到的未被更改前的旧值。
例如,test_and_set()获取到的是false,则先将false改为true,告诉其他线程锁已经被我占用了,再将返回获取到的false。
若其获取到的是true,还是会将标志位置为true,这就可以理解为不管获取到什么状态,都会将标志位强行置为true。返回true,继续忙等。
3.std::atomic_flag::clear(): 其作用就是重置标志位,将true置为false。与test_and_set()搭配使用。
注意事项
- 自旋锁适用于临界区执行时间短的场景,否则会浪费 CPU 资源。
- 内存序(如
std::memory_order_acquire和std::memory_order_release)用于控制原子操作的同步语义。
更多推荐


所有评论(0)