避免伪共享的关键是让不同线程访问的变量分属不同缓存行;现代CPU以64字节为缓存行单位,若逻辑无关变量被频繁修改且同处一行,会因MESI协议频繁同步而严重降速。
避免伪共享(False Sharing)的关键是让不同线程访问的变量不落在同一个缓存行(Cache Line)里。现代CPU以64字节为单位加载缓存行,若两个被不同线程频繁修改的变量恰好落在同一缓存行,即使它们逻辑上无关,也会因缓存一致性协议(如MESI)频繁同步,导致性能急剧下降。
结构体或类中相邻定义的变量容易被编译器连续分配,尤其当它们被不同线程写入时。例如:
// 危险:a 和 b 很可能在同一缓存行,被线程1和线程2分别修改
struct Counter {
int a; // 线程1写
int b; // 线程2写
};
用 alignas(64) 或填充字段(padding)将热点变量隔离到独立缓存行,是最直接有效的方式。
C++11 起支持 alignas,可确保变量起始地址按64字节对齐,天然避开与其他变量共享缓存行:
在关键变量前后插入足够字节的填充,确保它独占一个缓存行:
struct PaddedCounter {
char pad1[60]; // 填充至前一缓存行末尾
std::atomic
char pad2
[60]; // 防止后续成员挤进来
};
更稳健的做法是用 sizeof(std::atomic
比加 padding 更根本的解法是重构数据结构:
工具辅助:Linux 下可用 perf record -e cache-misses 结合火焰图定位高缓存失效热点;Intel VTune 也能识别 false sharing 模式。