多线程的伪共享

看书看到了伪共享,有必要整理一下,做一个阶段性的分析总结。

什么是共享?什么是伪共享?共享,很好理解,多个线程同时控制一个变量(数据)。比如在c++11中的shared_ptr;那么伪共享呢?这个不好理解,如果从字面意思上理解,就是表面是共享了数据(变量),但是实际上并没有被各个线程真正共享。

既然不好理解,那先举一个实际的例子,然后再总结。

假设有一个long型的数组long Data[4],有四个元素。它被程序装载到了一个拥有四个CPU的电脑,电脑的缓存有三级,即L1,L2,L3,其中L3是被共享的(这个大家如果不理解,可以看看较新的计算机原理的相关书籍)。大概类似于下面的图例:

现在问题来了,如果启动了四个线程分别操作Data[0]~Data[3],会出现什么情况呢?如果单纯从结果和流程上来看,一般看不出什么问题,数据在正常的操作,结果也是正确的。但是,如果换一个角度来看问题,就会发现了一些端倪。

把整个操作的流程耗费的时间打印下来,然后,再用一些特殊的操作(比如字节对齐或者填充一些没用的数据等),再按同样的方式执行这个程序,会发现,二者的时间流程大不一样,后者的要快很多?为什么?

这就引出了前面的说到的伪共享。在现代的计算机架构中,为了提高访问速度,使用了多级缓存机制,从寄存器操作数据开始,并不是直接操作内存,而要从上图中的一二三级缓存中操作,如果没有命中,才会去内存中操作,这就相当耗费时间了。但是以现代计算机的缓存命中率来看,特别是X86的基本可以做到八成以上。这已经是一个非常好的表现了,所以缓存机制有着很大优越性。

但是,正是因为缓存的存在,伪共享就会产生。在计算机的缓存中,并不是说你想多大或者多小就是多少,而有一个合理的范围,即缓存行,现代的计算机缓存设计基本是64字节的倍数(即缓存的大小是N=[64*M]*R,N:缓存大小 ,M:缓存行大小的倍数,N:行数),这样的话,再回头看举的例子,一般情况下,会被映射到一个缓存行中。也就是说,当多个CPU操作各自的缓存行时,它们的位置是一致的。这会导致什么情况?数据不一致,可是有人会问,我操作的不是一个地址啊,计算机不应该这么笨啊?对,所以计算机设计了一套应对的方法,这玩意儿同样助长了伪共享的阴暗的一面。

MESI协议和RFO请求,这是用来保证多个CPU操作同一缓存行时的强有力的手段。也即上面的例子中,同时访问一个数组的不同的索引位置,会把同一缓存行复制到不同的CPU中的缓存中去,但这时候儿就出现了一个问题,脏数据。也就是说,各个CPU无法判断另外一个CPU是否已经修改了这个数据,咋办?

MESI协议的基本内容如下:

M(Modified):修改,即本地处理器已经修改缓存行,形成了脏数据,缓存与请在内容已不一致;

E(Exclusive):专有,即缓存行内容和主存中保持一对待,且其它处理器都没有这行数据;

S(Shared):共享,即缓存行内容和主存中一致, 但不保证只有本处理器在处理此缓存行;

I(Invalid):失效,即缓存行失效, 不能使用。

具体的状态图和转换过程这里就不再详述,网上有相当清楚的资料,大家有兴趣可以看一看。这里只说一下一个最主要的产生伪共享的方式,即Remote Write,前面的例子提到的,当多个CPU拿到同一一个缓存行时,都想修改(虽然他们的数据地址,严格上不一致,但可惜,是同一个缓存行,可以简单理解成锁的粒度在这种情况下太大了),那么,每个CPU在修改前需要发出RFO(Request For Owner)请求,意思是说,你们都等等,我修改完成再说。即,申请拿到最高权限,排它的。这时候儿,别的处理器只能把自己的状态变成I(失效),等它完成别人同样进行如此的操作,看明白没,这玩意儿和锁有啥区别。只不过速度比OS的要快好多,但再快,还是比没有RFO要慢,所以这个是要很大的消耗CPU的性能的。

测试代码推荐:

https://www.cnblogs.com/RunForLove/p/5624390.html

不过这个是用JAVA写的。c++可以依照这个样子来一个。

正如上面所说,这个伪共享很难发现,因为毕竟消耗的时间也不是多大(虽然倍数较高,但是绝对时间并不多,而且不可能处处都是如此)。也就是说,它的问题没有想象的那么严重,所以在性能优化时,它不做为首选项来推荐。但是在一些高性能的场合,比如CPU和IO密集型的相关调度上,还是要有针对性的处理一下这个伪共享。

那么如何处理伪共享代码呢?

一是首先认真走查代码,二是可以采用一些手段,早期的可以使用填充,后期诸如JAVA或者C++11都提供了一些关键字或者方法,比如c++11的alignas(16)和Java JDK8的注解@sun.misc.Contended,都可以达到同样的目的。

最后总结一下,伪共享不是焦点,但在特定场合仍然要引起注意。伪共享的产生和现代计算机的缓存、MESI协议及RFO,特别是缓存中行粒度的大小这三者有者密不可分的关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值