Cache伪共享(False Sharing)问题浅析

1.问题

CPU的Cache以Line为单位与内存交换数据。对于代码中位置相近的变量,比如:

long a;

long b;

其在Cache中可能被放置在同一个Line中。在两颗CPU频繁访问不同变量的情况下,容易出现因为同一Line内容频繁做状态同步导致的性能下降问题,这个问题就称之为Cache伪共享问题。

举个例子,比如上面的两个变量。如果CPU0上的线程频繁使用变量a,CPU1上的线程频繁使用变量b,那么根军缓存一致性协议MESI,这个Line在不同CPU的Cache上进行同步的代价是很高的。

2. 分析

还是以第一部分的例子来分析。

初始状态,包含变量a和b的Line只存在于CPU0的缓存中。CPU0上的Line状态为E。

CPU1要对变量b写入,该Line被读入CPU1的Cache中。这时CPU0和CPU1该Line的状态都是S。因为CPU1要写入,写入后CPU1上的Line变为M,而CPU0上该Line同步更新状态为I。

之后CPU0要对变量a写入,CPU1上该Line内容会先写入内存,然后更新为I。CPU0对a写入后,CPU0上该Line的状态变为M。

再之后两颗CPU上频繁的对自己需要的变量进行访问和写入,该Line的状态会来回在M和I之间摆动。背后的代价是CPU之间频繁的发送总线读写消息进而使得程序运行效果变差。

3. 解决

如果开发面临类似的问题,主要是将两个变量之间“隔开”距离,使得它们不会被缓存在同一Line中。

可以使用编译器的align标签。如果是结构体,也可以在结构体size不到一个Line size(一般是32或64字节)的时候在结构体中添加一些字段,让两个结构体“隔开”。

4. 工具

Perf c2c命令可以检查这类情况。笔者开发中用的比较少,感兴趣的读者可以自行查找相关信息,网上相关资料非常多。

### 原理 Cache 是以 Cache Line 为单位去内存中取数据并且缓存数据的,一般来说 Cache Line 的大小为 64 字节。当访问 long 类型数组中某个成员时,CPU 会将临近的数组成员都加载到同一个 Cache Line 中,这样可以加速访问。当多个线程去同时读写共享变量时,由于缓存一致性协议,只要 Cache Line 中任一数据失效,整个 Cache Line 就会被置为失效。这就会导致本来相互不影响的数据,由于被分配在同一个 Cache Line 中,双方在写数据时,导致对方的 Cache Line 不断失效,无法利用 Cache Line 缓存特性,这种现象就被称为“共享” [^2][^3]。 ### 影响 共享会导致 Cache Line 被频繁的导入导出,造成很大的性能问题。因为当一个处理器修改了某个 Cache Line 中的数据时,其他处理器中对应的 Cache Line 会失效,需要重新从内存中加载数据,这增加了数据访问的延迟,降低了程序的性能 [^3]。 ### 解决方法 一种解决方法是进行 Cache Line 对齐,即通过合理定义数据结构,将不同线程访问的数据放置在不同的 Cache Line 中。例如,在结构体中添加填充变量。如在 `RingBufferFelds` 里面定义的变量用 `final` 修饰,意味着第一次加载之后不会再修改, 又由于「前后」各填充了 7 个不会被读写的 long 类型变量,所以无论怎么加载 Cache Line,这整个 Cache Line 里都没有会发生更新操作的数据,只要数据被频繁地读取访问,就自然没有数据被换出 Cache 的可能,也因此不会产生共享问题 [^5]。以下是一个简单的 C 语言示例代码: ```c #include <stdio.h> typedef struct { long x; long padding[7]; // 填充 7 个 long 变量以实现 Cacheline 对齐 long y; } CacheLineAlignedData; int main() { CacheLineAlignedData data; data.x = 10; data.y = 20; printf("x: %ld, y: %ld\n", data.x, data.y); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值