原子变量
原子变量(atomic variable)是 C++11 引入的一种同步机制,用于在多线程环境中进行无锁的、线程安全的操作。原子变量的操作是不可分割的,即在执行过程中不会被其他线程中断,从而避免了数据竞争和不一致的问题。原子变量位于 头文件中。
基本概念
原子性
原子性:一个操作是原子的,意味着它在执行过程中不会被其他线程中断。原子操作要么完全执行,要么完全不执行,不存在部分执行的状态。
数据竞争
数据竞争:当多个线程同时访问同一个内存位置,并且至少有一个线程在写入数据时,就会发生数据竞争。数据竞争可能导致未定义行为和数据不一致。
原子变量的类型
C++ 标准库提供了多种原子类型,包括:
std::atomic:模板类,可以用于任何可复制的类型 T。
特化类型:如 std::atomic_bool、std::atomic_int、std::atomic_uint 等。
基本用法
定义原子变量:
#include <atomic>
std::atomic<int> atomic_int;
std::atomic_bool atomic_bool;
原子操作
原子变量支持多种原子操作,包括:
加载(load):读取原子变量的值。
存储(store):写入原子变量的值。
交换(exchange):将原子变量的值替换为新值,并返回旧值。
比较交换(compare-exchange):如果原子变量的值等于预期值,则将其替换为新值,并返回操作是否成功。
#include <atomic>
#include <iostream>
int main() {
std::atomic<int> atomic_int(0);
// 加载操作
int value = atomic_int.load();
std::cout << "Loaded value: " << value << std::endl;
// 存储操作
atomic_int.store(42);
std::cout << "Stored value: " << atomic_int.load() << std::endl;
// 交换操作
int old_value = atomic_int.exchange(99);
std::cout << "Exchanged value: " << old_value << ", new value: " << atomic_int.load() << std::endl;
// 比较交换操作
int expected = 99;
bool success = atomic_int.compare_exchange_strong(expected, 100);
std::cout << "Compare-exchange result: " << success << ", expected: " << expected << ", new value: " << atomic_int.load() << std::endl;
return 0;
}
内存顺序
原子操作可以指定内存顺序(memory order),用于控制内存访问的顺序和可见性。C++ 提供了多种内存顺序选项,包括:
- std::memory_order_relaxed
特点:最宽松的内存顺序,不保证顺序和可见性。
用途:适用于不需要顺序保证的场景,如简单的计数器。 - std::memory_order_consume
特点:保证依赖关系的顺序。
用途:适用于依赖关系的数据依赖场景。 - std::memory_order_acquire
特点:保证读取操作的顺序。
用途:适用于读取操作需要顺序保证的场景。 - std::memory_order_release
特点:保证写入操作的顺序。
用途:适用于写入操作需要顺序保证的场景。 - std::memory_order_acq_rel
特点:同时保证读取和写入操作的顺序。
用途:适用于读取和写入操作都需要顺序保证的场景。 - std::memory_order_seq_cst
特点:最严格的内存顺序,保证所有线程看到的操作顺序一致。
用途:适用于需要最强顺序保证的场景。
#include <atomic>
#include <iostream>
int main() {
std::atomic<int> atomic_int(0);
// 使用 memory_order_seq_cst 进行存储操作
atomic_int.store(42, std::memory_order_seq_cst);
// 使用 memory_order_seq_cst 进行加载操作
int value = atomic_int.load(std::memory_order_seq_cst);
std::cout << "Loaded value: " << value << std::endl;
return 0;
}
示例代码
以下是一个完整的示例,展示了如何在多线程环境中使用原子变量进行线程安全的计数:
#include <atomic>
#include <iostream>
#include <thread>
#include <vector>
std::atomic<int> counter(0);
void increment_counter() {
for (int i = 0; i < 1000; ++i) {
counter.fetch_add(1, std::memory_order_relaxed);
}
}
int main() {
std::vector<std::thread> threads;
// 创建多个线程进行计数
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment_counter);
}
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
// 输出最终计数结果
std::cout << "Final counter value: " << counter.load() << std::endl;
return 0;
}
Final counter value: 10000
总结
原子变量:用于在多线程环境中进行无锁的、线程安全的操作。
原子性:确保操作是不可分割的,避免数据竞争和不一致。
内存顺序:控制内存访问的顺序和可见性,提供多种选项以满足不同需求。
应用场景:适用于需要线程安全的计数器、标志位等场景。