std::atomic
std::atomic 完整使用指南
std::atomic 提供了线程安全的原子操作,无需使用互斥锁。下面是详细的使用方法。
基础操作
1. 声明和初始化
#include <atomic>
// 基本类型
std::atomic<int> count{0};
std::atomic<bool> is_ready{false};
std::atomic<ConnectionState> state{ConnectionState::Disconnected};
// 指针类型
std::atomic<int*> ptr{nullptr};
// 自定义类型需要满足 TriviallyCopyable
struct Status {
int code;
bool success;
};
std::atomic<Status> status{Status{0, false}};
2. 基本读写操作
// 存储(写)
state.store(ConnectionState::LoggedIn); // 默认顺序
state.store(ConnectionState::LoggedIn, std::memory_order_release); // 指定内存序
// 加载(读)
auto s = state.load(); // 默认顺序
auto s = state.load(std::memory_order_acquire); // 指定内存序
// 直接赋值和转换(运算符重载)
state = ConnectionState::LoggedIn; // 等同于 store
ConnectionState s = state; // 等同于 load
3. 修改操作
std::atomic<int> counter{0};
// 后置自增/自减
int old = counter++; // 返回旧值,然后+1
int old = counter--; // 返回旧值,然后-1
// 前置自增/自减
int new_val = ++counter; // +1后返回新值
int new_val = --counter; // -1后返回新值
// 原子加/减
int old = counter.fetch_add(5); // 返回旧值,然后+5
int old = counter.fetch_sub(3); // 返回旧值,然后-3
// 原子位运算
int old = counter.fetch_or(0xFF); // 按位或
int old = counter.fetch_and(0x00); // 按位与
int old = counter.fetch_xor(0xFF); // 按位异或
CAS(Compare-And-Swap)操作
这是最强大的原子操作,用于无锁编程。
std::atomic<int> value{10};
// compare_exchange_strong(强版本)
int expected = 10;
// 如果 value == expected,则设置 value = 20,返回 true
// 否则 expected = value,返回 false
bool success = value.compare_exchange_strong(expected, 20);
if (success) {
// 成功修改为20
} else {
// 修改失败,expected现在等于value的实际值
std::cout << "实际值是: " << expected << std::endl;
}
// compare_exchange_weak(弱版本,可能虚假失败)
// 适用于循环操作
expected = 20;
while (!value.compare_exchange_weak(expected, 30)) {
// 虚假失败或值已改变,expected已更新
// 可以在这里添加重试逻辑
}
实际应用示例
示例1:状态机转换(最常用)
enum class ConnectionState {
Disconnected, Connecting, Connected, LoggingIn, LoggedIn
};
class StateMachine {
private:
std::atomic<ConnectionState> state_{ConnectionState::Disconnected};
public:
// 尝试转换状态(原子操作)
bool transition_to(ConnectionState new_state) {
ConnectionState expected = get_state();
// 检查状态转换是否合法
switch (expected) {
case ConnectionState::Disconnected:
if (new_state != ConnectionState::Connecting) return false;
break;
case ConnectionState::Connecting:
if (new_state != ConnectionState::Connected &&
new_state != ConnectionState::Disconnected) return false;
break;
// ... 其他状态检查
}
// 原子地执行转换
return state_.compare_exchange_strong(expected, new_state);
}
// 更安全的方式:只在特定状态转换
bool transition_if(ConnectionState expected, ConnectionState desired) {
return state_.compare_exchange_strong(expected, desired);
}
ConnectionState get_state() const {
return state_.load(std::memory_order_acquire);
}
void set_state(ConnectionState new_state) {
state_.store(new_state, std::memory_order_release);
}
};
示例2:线程安全的计数器
class RequestCounter {
private:
std::atomic<uint64_t> counter_{0};
std::atomic<uint64_t> max_concurrent_{0};
std::atomic<uint64_t> current_{0};
public:
uint64_t increment() {
uint64_t old = current_.fetch_add(1, std::memory_order_acq_rel);
uint64_t new_val = old + 1;
// 更新最大值
uint64_t cur_max = max_concurrent_.load(std::memory_order_relaxed);
while (new_val > cur_max) {
if (max_concurrent_.compare_exchange_weak(cur_max, new_val)) {
break;
}
}
return new_val;
}
uint64_t decrement() {
return current_.fetch_sub(1, std::memory_order_acq_rel) - 1;
}
uint64_t get_current() const {
return current_.load(std::memory_order_acquire);
}
uint64_t get_max() const {
return max_concurrent_.load(std::memory_order_relaxed);
}
};
示例3:单例模式(双重检查锁定)
class Singleton {
private:
static std::atomic<Singleton*> instance_;
static std::mutex mutex_;
Singleton() = default;
public:
static Singleton* get_instance() {
Singleton* ptr = instance_.load(std::memory_order_acquire);
if (!ptr) {
std::lock_guard<std::mutex> lock(mutex_);
ptr = instance_.load(std::memory_order_relaxed);
if (!ptr) {
ptr = new Singleton();
instance_.store(ptr, std::memory_order_release);
}
}
return ptr;
}
};
std::atomic<Singleton*> Singleton::instance_{nullptr};
示例4:无锁队列的简化实现
template<typename T>
class LockFreeQueue {
private:
struct Node {
T data;
std::atomic<Node*> next;
Node(const T& d) : data(d), next(nullptr) {}
};
std::atomic<Node*> head_;
std::atomic<Node*> tail_;
public:
LockFreeQueue() {
Node* dummy = new Node(T());
head_.store(dummy, std::memory_order_relaxed);
tail_.store(dummy, std::memory_order_relaxed);
}
void push(const T& value) {
Node* new_node = new Node(value);
while (true) {
Node* tail = tail_.load(std::memory_order_acquire);
Node* next = tail->next.load(std::memory_order_acquire);
if (tail != tail_.load(std::memory_order_relaxed)) {
continue; // tail被修改
}
if (next != nullptr) {
// 帮助推进tail
tail_.compare_exchange_weak(tail, next);
continue;
}
// 尝试链接新节点
if (tail->next.compare_exchange_weak(next, new_node)) {
// 成功,推进tail
tail_.compare_exchange_weak(tail, new_node);
break;
}
}
}
bool pop(T& result) {
while (true) {
Node* head = head_.load(std::memory_order_acquire);
Node* tail = tail_.load(std::memory_order_acquire);
Node* next = head->next.load(std::memory_order_acquire);
if (head != head_.load(std::memory_order_relaxed)) {
continue;
}
if (head == tail) {
if (next == nullptr) {
return false; // 队列为空
}
// 推进tail
tail_.compare_exchange_weak(tail, next);
continue;
}
// 读取数据
result = next->data;
// 移动head
if (head_.compare_exchange_weak(head, next)) {
delete head;
return true;
}
}
}
};
内存序(Memory Order)详解
// 1. relaxed - 最宽松,只保证原子性,不保证顺序
std::atomic<int> x{0}, y{0};
x.store(1, std::memory_order_relaxed);
y.store(2, std::memory_order_relaxed);
// 其他线程可能看到 y=2 而 x=0
// 2. release/acquire - 同步操作
// 线程A
data = 100;
ready.store(true, std::memory_order_release); // 之前的写入都完成
// 线程B
while (!ready.load(std::memory_order_acquire)); // 确保看到release前的所有写入
assert(data == 100); // 保证成功
// 3. seq_cst - 最严格,全局顺序一致(默认)
std::atomic<bool> x{false}, y{false};
// 线程1
x.store(true, std::memory_order_seq_cst);
// 线程2
y.store(true, std::memory_order_seq_cst);
// 线程3
while (!x.load(std::memory_order_seq_cst));
if (y.load(std::memory_order_seq_cst)) {
// 保证看到一致顺序
}
在 Asio 网络程序中的实用模式
class NetworkClient {
private:
std::atomic<ConnectionState> state_{ConnectionState::Disconnected};
std::atomic<uint64_t> request_id_{0};
std::atomic<bool> should_stop_{false};
public:
// 快速状态检查(高频调用)
bool is_ready() const {
// 对于简单的bool检查,relaxed足够
auto s = state_.load(std::memory_order_relaxed);
return s == ConnectionState::LoggedIn;
}
// 安全的操作前检查
asio::awaitable<void> send_request(const Request& req) {
// 获取当前状态
auto s = state_.load(std::memory_order_acquire);
if (s != ConnectionState::LoggedIn) {
// 缓存请求
cache_request(req);
co_return;
}
// 生成请求ID
uint64_t id = request_id_.fetch_add(1, std::memory_order_relaxed);
// 发送数据...
co_await do_send(req);
}
// 状态转换(带重试)
bool try_set_state(ConnectionState expected, ConnectionState desired) {
return state_.compare_exchange_strong(expected, desired,
std::memory_order_acq_rel);
}
// 优雅关闭
void shutdown() {
should_stop_.store(true, std::memory_order_release);
}
bool should_stop() const {
return should_stop_.load(std::memory_order_acquire);
}
};
性能提示
- 默认使用
seq_cst是最安全的,但性能开销最大 - 计数器使用
relaxed:counter.fetch_add(1, std::memory_order_relaxed) - 标志位使用
release/acquire:生产者-消费者模式 - 避免在循环中使用
seq_cst,除非真的需要全局顺序 - 优先使用
compare_exchange_weak在循环中(可能虚假失败但性能更好)
这样你就可以在多线程环境中安全地管理连接状态了!
std::atomic 是 C++11 标准 正式引入的。这意味着,如果你的编译器支持 C++11(如 GCC 4.8+、Clang 3.6+、MSVC 2015+),就可以直接使用它。
各标准版本的支持演进
| 标准版本 | 主要更新内容 |
|---|---|
| C++11 | 首次引入 std::atomic 模板,支持布尔、整型和指针类型 |
| C++20 | 增加对 float、double 等浮点类型的特化支持;增加对 std::shared_ptr<T> 和 std::weak_ptr<T> 的特化支持;默认构造函数变为 constexpr |
| C++23 | 提供 _Atomic(T) 宏以兼容 C 的 stdatomic.h 头文件 |
兼容性说明
- C++11 及以上:可直接使用
#include <atomic>和std::atomic<T>,这是推荐的方式 - C++98/03:标准库中没有
std::atomic,如需使用原子操作,只能借助编译器内置函数(如 GCC 的__sync_*或__atomic_*系列)或平台相关 API(如 Windows 的InterlockedExchange),或使用第三方库如 Boost.Atomic 作为过渡方案
类型限制提醒
std::atomic<T> 要求 T 满足 可平凡复制(TriviallyCopyable)的条件。像 std::string 或 std::vector 这类类型不能直接使用,这在选择状态枚举类型时没有问题,但如果想原子化更大的结构体,需要先确认其满足该条件。
简单来说,只要项目配置在 C++11 或更高标准,就可以放心使用 std::atomic 来管理线程间的状态同步。
浙公网安备 33010602011771号