C++ 原子操作
什么是原子操作?
在多线程编程中,当多个线程同时访问共享数据时,如果不加以控制,往往会导致数据竞争(Data Race)和不可预期的结果。原子操作就是一种能够在多线程环境中安全地进行读写操作的机制,它保证了操作的不可分割性,也就是说,一个原子操作要么完全执行完毕,要么完全不执行,中间状态对其他线程是不可见的。
备注
原子(Atomic)一词来源于希腊语"atomos",意为"不可分割的",这也正是原子操作的本质特点。
C++ 11中的原子支持
C++11标准引入了对原子操作的直接支持,主要通过<atomic>
头文件提供。这个库定义了多个原子类型以及对它们的操作函数,使我们可以在不使用互斥锁的情况下实现线程安全的数据访问。
核心原子类型
C++标准库提供了几种常用的原子类型:
std::atomic<T>
- 可以将任何类型T变为原子类型std::atomic_flag
- 一个简单的布尔原子类型std::atomic_bool
,std::atomic_int
,std::atomic_uint
, 等等 - 常用基本类型的原子版本
基本原子操作示例
让我们从一个简单的例子开始,展示原子操作的基本用法:
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
std::atomic<int> counter(0); // 原子计数器
void increment_counter() {
for (int i = 0; i < 10000; ++i) {
counter++; // 原子递增操作
}
}
int main() {
std::vector<std::thread> threads;
// 创建5个线程,每个线程递增计数器10000次
for (int i = 0; i < 5; ++i) {
threads.push_back(std::thread(increment_counter));
}
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
std::cout << "最终计数值: " << counter << std::endl;
return 0;
}
输出结果:
最终计数值: 50000
在这个例子中,我们创建了一个原子整型变量counter
,然后启动5个线程,每个线程递增这个计数器10000次。由于counter
是原子类型,所以所有的递增操作都是安全的,最终结果总是准确的50000。
如果我们使用普通的int
而不是std::atomic<int>
,就会出现数据竞争,最终结果通常会小于50000,因为不同线程的递增操作可能会相互覆盖。