免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
31 [报告]
发表于 2011-10-14 18:22 |只看该作者
本帖最后由 zylthinking 于 2011-10-14 18:30 编辑
回复  zylthinking


    这种程序员不够格写多线程程序吧
smalloc 发表于 2011-10-14 18:16


这种程序员正是本人, 不知道是不是 arm 和 x86 一样也是 顺序写保证的, 就目前而言, 日活跃36000人左右, 3个月过去了, 还没有人为这个报 error

论坛徽章:
0
32 [报告]
发表于 2011-10-14 18:40 |只看该作者
回复 27# zylthinking

hoh, 假设单cpu上,p=malloc enable=1两条指令被编译器优化交换顺序了,那么线程1执行了enable=1之后(p=malloc还没有执行),产生中断调度了第二个县城执行,第二个县城直接访问p不就非法访问了?

论坛徽章:
0
33 [报告]
发表于 2011-10-14 18:43 |只看该作者
回复 31# zylthinking


    你说x86保证顺序写,那也得给他优化屏障吧才有用吧。

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
34 [报告]
发表于 2011-10-14 18:44 |只看该作者
回复  zylthinking

hoh, 假设单cpu上,p=malloc enable=1两条指令被编译器优化交换顺序了,那么线程1执 ...
ruslin 发表于 2011-10-14 18:40


这个有可能, 我听到过很多 O3 优化出现问题的话, 现在我考虑的是CPU的乱序执行会不会导致 crash, 因为我实在很好奇为什么它不出问题

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
35 [报告]
发表于 2011-10-14 19:13 |只看该作者
就等你呢, 那么现在一个基本问题: 缺乏 barrier 造成的代码重排, 可能导致
thread A:

ptr->buf  ...
zylthinking 发表于 2011-10-14 16:22



1) 先说thread A和thread B,单核。

     我认为thread A是需要barrier的,但是thread B是不需要的。

    thread B两个指令间,存在control dependency,这种情况就我知道的知识范围中,编译器是不会重新排序的。


2) 然后说CPU A和CPU B,多核。

   x86我不大了解,搞不定。只说使用weak order的CPU。




   CPU A需要加wmb()或者mb(),这个指令要求buf先写完后,再写flag。   

   如果不加wmb/mb的话:

   a) 在ARM等基于bus boardcast的SMP中,向各个CPU提交本次写操作所对应的invalidate request这个动作,是原子的,即所有CPU同时收到这个invalidate request。因此,所有CPU以同样的顺序,要么先看到写buf对应的invalidate request,要么先看到写flag对应的invalidate request。

   b) 在NUMA结构中,向各个CPU提交本次写操作所对应的invalidate request这个动作,它不是原子的。即有的CPU会先看到buf对应的invalidate request,有的CPU会先看到flag对应的invalidate request。只有加入wmb()/mb(),才能保证所有CPU先收到buf对应的invalidate request,再收到flag对应的invalidate request。



   到了CPU B这里,CPU B同样也会看到这两条指令间的control dependency,而且第二条指令是个写操作。

   大部分CPU都有预读这个功能,但是好像没有CPU会预写,因为预写写错了的话,没法撤销。

   所以CPU B会老老实实的先执行读flag。


   
   但是即使CPU B先读flag,还是有的CPU不要求有rmb()/mb(),有的则要求。

   先说不要求的,大部分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。

  
   但是linux kernel的内存模型是基于alpha的,alpha的CPU B中,必须加入rmb()/mb()。

   因为CPU对cache的读写端口越多越好,可以同时执行更多的读写操作。但是作为cache的RAM,其读写端口越多就设计越复杂,所以alpha用了两个RAM,使读写端口数量增加了一倍,带来的问题是有了两个incoming queue,因此没办法保证处理invalidate request及read reply的顺序,或者说它的incoming queue总是乱排序的,这样就不能保证看到后提交的invalidate request时,必然已经看到了先提交的invalidate request。

   解决的办法就是在读完flag后,程序主动执行rmb(),主动的处理所有invalidate request,这样才能保证看到flag的新值时,必然能看到buf的新值。

   体现在kernel中,就是RCU的读,好像叫rcu_dereference????   
  
   RCU写时,写结构,执行mb(),写结构的指针。
  
   RCU读时,一般的CPU只要能读到结构的指针,则必然能读到结构的内容;但是alpha则不然,它在读结构的指针和读结构之间,必须加入一个rmb()。

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
36 [报告]
发表于 2011-10-14 19:21 |只看该作者
1) 先说thread A和thread B,单核。

     我认为thread A是需要barrier的,但是thread B是不需要 ...
塑料袋 发表于 2011-10-14 19:13



thanks, 传闻要下雨了, 回家拜读

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
37 [报告]
发表于 2011-10-14 19:27 |只看该作者
下雨也不能阻挡我去东莞的心!

我去长安镇的康城名仕桑拿了,那里有情景房,我预订了个教室房,一会有老师上课。

论坛徽章:
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
38 [报告]
发表于 2011-10-14 20:29 |只看该作者
回复 35# 塑料袋

非常感谢您的精辟回复,完全理解了这个问题,实在很感激!

另外大家可以参阅kouu的blog中翻译的kernel中Document/memory-barriers.txt,里面译者的注释也有助于大家理解内存屏障!
http://blog.chinaunix.net/space. ... blog&id=1640912

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
39 [报告]
发表于 2011-10-14 23:36 |只看该作者
回复 35# 塑料袋


    根据你说的,我的理解是:
    多核+arm时A要加
   多核+alpha时A要加,且B也要加.

    不知我的理解是否正确,
    但我也有lz的疑惑,就是感觉在用户空间写代码都没有考虑屏障这个问题,但是也从没听说由此导致的问题.
    请指点下,谢谢.

论坛徽章:
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
40 [报告]
发表于 2011-10-15 09:28 |只看该作者
本帖最后由 asuka2001 于 2011-10-15 09:44 编辑

invalidate request代表的是CPUA向内存系统提交了自己的store请求,代表的其他CPU如CPUB“可以”感知到store的地址上的数据发生了变化,invalidate request的处理,代表的是CPUB实际认识到CPUA store的地址上的数据发生了变化。可以感知和实际感知的顺序是可以有区别的。。。

就我的理解是因为x86保证写有序,也就是说发送出的invalidate request和对它的处理都应该是有序的:这个仅仅是我的猜测,如果发送出的invalidate request是乱序的,CPUA就得加wmb();如果对invalidate request的处理是乱序的那CPUB得加rmb()。

如果都是有序的,那么CPUA的store就是有序的,它一定会先保存ptr->buf的值,然后保存ptr->enable的值;CPUB的视角上则是因果一致的,即看到了后store的ptr->enable的最新值1,那么先store的ptr->buf的最新值一定能被看到。

CPUA上的wmb()是为了保证你的写有序,而CPUB上的rmb()是为了保证它的视角因果一致。。。所以由于x86的体系特征,我们就不用考虑加wmb()和rmb()也同样能保证代码的正确性。

仅仅个人观点,都是自己的猜测,有误还请指点!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP