免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: zylthinking
打印 上一主题 下一主题

为什么用户空间程序不用考虑内存屏障? [复制链接]

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
101 [报告]
发表于 2013-04-19 10:08 |只看该作者
本帖最后由 arm-linux-gcc 于 2013-04-19 10:10 编辑

回复 1# zylthinking

对屏障我没什么研究,但是我觉得LZ的问题应该从汇编指令这个层次上来探讨这个问题
a = 1;        //这条C代码语句并不是一条汇编指令就能够完成的

arm里面对一个变量赋值,是需要先从内存装载到通用寄存器,计算完之后在填回内存
所以a = 1;这种代码,汇编应该是:
ldr r0, #1        //把立即数1填到r0
str r0, [变量a的地址]         //把r0中的内容填到变量a的地址去(可能是填进了内存,也可能是填进了cache,后面的讨论就假设是读写的cache)



我说明一下我的理解

把LZ代码简化一下
thread a(core 0)              thread b(core 1)
y = 1;                 if (x == 2)
x = 2;                     z = y;
                          else
                              z = 0;

由于乱序,假如线程a中的两句颠倒了,在两个核中的实际运行情况如下
thread a(core 0)              thread b(core 1)
x = 2;                            if (x == 2)
y = 1;                                z = y;
                                     else
                                         z = 0;

把实际运行情况(线程a中的两句由于乱序发生了颠倒)展开成汇编
cycle                      core 0                                     core 1
--------------------------------------------------------------------------------------
0                           ldr r0, #2                                ......
1                           str r0, [变量x的地址]                  ......                           //这里把r0写入cache,要注意这句执行完以后,cache中x的值才会为2,
                                                                                                            //也就是说core 1必须在下一个周期去取,得到的才会是2
2                           ldr r1, #1                                ldr r0, [变量x的地址]     //假如这一句在cycle 2这个时刻之前执行了,那么后面的判断必然不成立
3                           str r1, [变量y的地址]                 cmp r0, #2                  //比较变量x是不是等于2
4                           ......                                       bne balabalabala        //如果不等则跳到后面balabalabala处,如果相等则不跳转(继续执行紧接着的后面的一条指令)
5                           ......                                      ldr r1, [变量y的地址]       //对比core 0中的情况,在core 1这里取y值时,core 0早就把y值写到cache了
6                           ......                                       str r1, [变量z的地址]
balabalabala                                                         

所以这种情况不加屏障也是没有问题的,但是使用mutex仍然更保险一下
不知道能否解释LZ提出的问题







论坛徽章:
0
102 [报告]
发表于 2014-08-23 13:02 |只看该作者
本帖最后由 yiifburj 于 2014-08-23 13:37 编辑

我研究了一下, 发表一下个人观点
1 用户态其实是单cpu的, 经过我的多线程实验发现, 无论多少线程, cpu使用率只能达到25%, 4核, 说明不存在cpu之间的竞争。
2 编译器可能乱序,cpu也可能会乱序, 还是有风险的, 但是不容易碰到, 原因见4.
3 我做了一个实验,人工将ptr->enable = true;(我的代码中是a=1;)放到前面, 一般编译器乱序是为了优化,我后面的代码是先使用a, 等待一段时间, 再使用指针,这样无论编译器是否优化, 都是a=1;先执行, 理论上, 另一个cpu一定会访问非法地址,我用了一个assert, 但是进程没死,反复执行,都不死, 奇怪的事情!!!!
4 我的一个猜测, 想不出其他的解释了, 一个cpu切换线程一般是经过一段时间再切换,虽然a=1先执行, 但是执行a=1这个线程拥有的这段时间内足够将=malloc也执行完毕, 所以当另一个线程发现a=1的时候, ptr是正常的, 不是非法地址。

5 总结, 用户态程序有bug, 但是这种bug碰到的情况应该比中500万的概率都低, 所以忽视着, 但没问题。

论坛徽章:
2
射手座
日期:2014-09-03 00:18:022015年辞旧岁徽章
日期:2015-03-03 16:54:15
103 [报告]
发表于 2014-08-25 18:20 |只看该作者
本帖最后由 wLiu2007 于 2014-08-25 20:41 编辑

回复 35# 塑料袋

先说不要求的,大部分CPU在逻辑上,有且仅有一个incoming queue,里边存放收到的各invalidate request,以及read reply等。
这个incoming queue的真实情况是相邻的invalidate request可以重新排序,但是invalidate request及read reply之间,绝对不能重新排序。为了好理解,你可以认为这个incoming queue从不重新排序,这个是最直接的设计方法。
如果从不重新排序的话,那么就可以保证,在看到后提交的invalidate request时,必然已经看到了先提交的invalidate request。如果CPU A加了wmb()/mb()的话,就是说CPU B看到对flag的写时,必然已经看到wmb()之前的写操作。
这个的典型就是cortex-a9


@塑料袋,

请教一个问题:
lz举得例子,因为thread B里面指令1和指令2存在control dependence,所以编译器保证了指令1和指令2的编译顺序;所以这里不用加任何屏障也能保证正确性;

假如thread B的两个指令不存在control /data dependence,那么这里在thread B中只需要加一个编译屏障保证编译顺序即可吧,不用加读屏障吧
A=1; B=2;
在thread A上
store A = 4;
写屏障;
store B = 5;

在thread B上:
load B;
这里需要加入编译屏障即可,不用加读屏障;
load A;

这样在arm这种平台上就能保证当B=5的时候,读出来A一定是4;

如果是Alpha平台的话,thread B这里放优化屏障不能保证吧,必须用读屏障才行;


   

论坛徽章:
0
104 [报告]
发表于 2014-08-26 11:06 |只看该作者
本帖最后由 l4rmbr 于 2014-08-26 11:08 编辑

要考虑用户程序跑在什么样层次的抽象机器上这个问题。

用户程序可能用C,C++,  Java.  每种语言的编译器与运行时机器,构架了一个在操作系统之上的更高层次的机器。
每种语言都定义了自己的内存一致性模型,所以,乱序的事情在语言编译器层次已经被考虑,用户可以不用费心。
用户只需要考虑事务逻辑上的互斥机制即可(比如对一个共享资源的访问,用户程序必须自己显式的用互斥机制)。

论坛徽章:
0
105 [报告]
发表于 2015-03-21 13:27 |只看该作者
我的观点:
1、用户态程序员如果还要考虑这么底层的事情,那么负担很大,编个程序也得处处担心。
2、如果仅从逻辑上来讲(不考虑什么乱序情况),如果flag只会从0->1改变一次,我觉得这样代码没必要加锁,就算线程B读出来的flag值不正确,也只是已经变成1了但读到的是0的这种情况,也不会导致段错误。

论坛徽章:
0
106 [报告]
发表于 2015-07-06 12:06 |只看该作者
回复 102# yiifburj


    貌似真是有问题, 现在测试发现, 多线程是可能多核的. bug bug bug
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP