当年我们学 atomic。
学到最后会有一种无奈。
“我想要原子。”
“但我不想把类型改成 atomic。”
因为一改。
接口全变。
结构体布局也可能变。
当年:想原子就得改数据结构
#include <atomic>
struct Stats {
std::atomic<int> hits;
};
这当然可以。
但你在现实里经常遇到另一种情况。
数据结构是别人定义的。
你改不了。
或者你不敢改。
线上啪一下:多线程累加偶发丢数
你写了个小项目。
统计访问次数。
struct Stats {
int hits = 0;
};
void on_request(Stats& s) {
++s.hits;
}
单线程没问题。
多线程下。
你会偶发丢增量。
而且很难复现。
C++20:std::atomic_ref
atomic_ref<T> 可以把一个现有的 T。
当成原子来操作。
#include <atomic>
void on_request(Stats& s) {
std::atomic_ref<int> hits(s.hits);
hits.fetch_add(1, std::memory_order_relaxed);
}
你没有改 Stats 的定义。
但你在这个函数里。
把 hits 当成原子用。
你刚学 C++ 会卡:这是不是把数据复制了一份
不是。
它不是拷贝。
它引用的是原来的对象。
它更像一个“原子操作的视图”。
但它有边界
atomic_ref 对齐要求更严格。
类型也得是可平凡拷贝(trivially copyable)那类。
你可以把它理解成。
原子操作需要硬件支持。
硬件对内存对齐很挑。
关键结论
atomic_ref 解决的是“我想原子,但我不想改类型”。
小结
如果你在给老代码补并发安全。
atomic_ref 很像一个救命工具。
它不改变结构。
但能改变你对字段的访问方式。