免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2017 | 回复: 7
打印 上一主题 下一主题

[内存管理] 关于内存屏障的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-03-23 18:40 |只看该作者 |倒序浏览
请教一个关于内存屏障的问题:
有2个全局变量,初始值a=b=0;CPU1对这2个变量执行写操作,cpu2读这2个变量;每个cpu有自己独立的cache, 不使用内存屏障

当在cpu1上执行写操作:
a=4;
b=5;
通过汇编指令能看到两条语句的顺序与C代码一致,即先给a赋值,后给b赋值;(编译顺序得到保障

在cpu2上执行如下读操作,读的汇编指令顺序也得到保证
c=b; //读出来是5;
d=a;

想请教一下,当c读出来是5的时候,d读出来一定是4还是有可能是0?

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
2 [报告]
发表于 2014-03-24 09:57 |只看该作者
回复 1# Huntsmen

编译顺序不等于执行顺序

执行顺序不等于可感知(observe)顺序

可感知顺序不等于被感知顺序

所以 d即可以是4也可以是0

论坛徽章:
0
3 [报告]
发表于 2014-03-24 10:41 |只看该作者
critical section

這時候就是spin lock的用處了

所以妳可以看到在 kernel source code上的全域變數

在讀寫時都會lock/unlock住

论坛徽章:
0
4 [报告]
发表于 2014-03-24 20:56 |只看该作者
回复 1# Huntsmen


内存屏障的目的是为了防止CPU乱序,不是防止编译器优化,这应该是两个概念。
X86上,写不会乱序,所以CPU2上d一定是在c的后面被赋值;
但是CPU2上读有可能会乱序,即CPU2上读a的操作可能会在读b之前发生,那么就算假定c读出来是5,也不能保证a读出来是4.

个人理解,不一定对。。。


   

论坛徽章:
0
5 [报告]
发表于 2014-03-24 22:40 |只看该作者
本帖最后由 l4rmbr 于 2014-03-24 22:41 编辑

回复 1# Huntsmen

Huntsmen,

1. 编译顺序得到保证,仅说明在编译器层次没有乱序,但无法约束最终在CPU上执行时的顺序,所以可能在CPU1上对a,b的赋值顺序是相反
    的,这样,在CPU2上,虽然读到b值是5, 仍可能读到a值是0。

2. 退一步,即使在CPU1上执行时顺序依旧跟程序顺序一致,仍不能保证读到a值为0。 因为CPU存在局部缓存。假如a,b存在于CPU2
   上不同的缓存行。当CPU1上更新了a,b值, 缓存一致性系统开始更新CPU2上缓存的值, 在要更新b所在缓存行时,总线一直忙,导致
   b的旧值被观测到。 这是可能的,因为缓存一致性系统只保证缓存最终会生效,但它不保证顺序,不保证原子性。

所以,必要的内存屏障是一定需要的,以保证行为的正确。
   

论坛徽章:
0
6 [报告]
发表于 2014-03-24 23:36 |只看该作者
假设一个前提条件,上面的编译顺序和执行顺序都得到保障;
cpu1上先修改a,后修改b;然后会发信号给cpu2,让其对应的cache失效;发送的cache line失效的信号也是先a,后b;
在cpu2上,虽然也是先收到a失效通知,后收到b失效通知,但是很可能a所在的cache line正在被总线访问(忙状态),需要等到总线访问结束之后才能失效,而b所在的cache line没有被访问,b可以马上失效;
所以即使cpu2上的执行顺序是c=b;d=a;得到保障, 这种场景c=b=5新值, 而d=a=0旧值;


另外在请教下:
内存屏障这个东西,需要cpu提供特殊的指令来支持吗?

论坛徽章:
0
7 [报告]
发表于 2014-03-24 23:47 |只看该作者
回复 6# Huntsmen

需要。我只知道x86架构上的。

lock指令前缀,读写内存的指令在发起时,处理器会向总线发出一个lock#的信号,阻塞住其它内存访问请求,它禁止处理器乱序,并保证内存访问操作会以同样的顺序被其他处理器观察到。这种做法就实现了内存屏障的作用。

对于支持SSE/SSE2/SSE3/SSE4特性的处理器, mfence, lfence, sfence指令分别实现了通用屏障(读和写),读屏障,写屏障的语义。


   

论坛徽章:
0
8 [报告]
发表于 2014-03-25 15:38 |只看该作者
l4rmbr 发表于 2014-03-24 23:47
回复 6# Huntsmen

需要。我只知道x86架构上的。


同意。
另外IA上还有一些可以达到内存屏障的指令,包括:
INVD, INVEPT, INVLPG, INVVPID, LGDT, LIDT, LLDT, LTR, MOV to CR0,1,2,3 ..., MOV to DR0,1,2,3..., WBINVD, and WRMSR3. CPUID, IRET, RSM 。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP