免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 3369 | 回复: 22

[C++] 请教一个c++11 memory-ordering 的问题 [复制链接]

论坛徽章:
12
2015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之同曦
日期:2017-03-17 19:13:162016科比退役纪念章
日期:2016-11-07 08:28:12luobin
日期:2016-06-17 17:46:36wusuopu
日期:2016-06-17 17:43:4515-16赛季CBA联赛之福建
日期:2016-01-14 12:49:22程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:002015年亚洲杯之科威特
日期:2015-03-24 14:21:272015年迎新春徽章
日期:2015-03-04 09:57:092016科比退役纪念章
日期:2018-04-10 16:20:18
发表于 2016-11-05 13:27 |显示全部楼层
void push(T const& data)
{
    counted_node_ptr new_node;

    new_node.ptr = new node(data);

    new_node.external_count = 1;

    new_node.ptr->next = head.load(std::memory_order_relaxed)

    while( !head.compare_exchange_weak(new_node.ptr->next,  
                                                                   new_node,
                                                                   std::memory_order_release,
                                                                   std::memory_order_relaxed) ) ;
}


C++ concurrency in action 书上的一段代码。

感觉

head.load(std::memory_order_relaxed)



while( !head.compare_exchange_weak(new_node.ptr->next,  
                                                                   new_node,
                                                                   std::memory_order_release,
                                                                   std::memory_order_relaxed) ) ;

指定 memory_order 参数并不会有什么影响,和 memory_order_seq_cst 好像没什么区别。

都是对同一个原子变量 head 做操作。

大牛指教。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
发表于 2016-11-05 13:56 |显示全部楼层
std::memory_order_release会让其它CPU看到exchange之后的结果。
memory_order_seq_cst是最强的保障,一般而言会比memory_order_release贵,在这里用memory_order_release就够了,当然你都用memory_order_seq_cst也没错,就是会慢一点而已。

论坛徽章:
12
2015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之同曦
日期:2017-03-17 19:13:162016科比退役纪念章
日期:2016-11-07 08:28:12luobin
日期:2016-06-17 17:46:36wusuopu
日期:2016-06-17 17:43:4515-16赛季CBA联赛之福建
日期:2016-01-14 12:49:22程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:002015年亚洲杯之科威特
日期:2015-03-24 14:21:272015年迎新春徽章
日期:2015-03-04 09:57:092016科比退役纪念章
日期:2018-04-10 16:20:18
发表于 2016-11-05 14:20 |显示全部楼层
回复 2# windoze

多谢,你说的这些我知道,不过其实还是有问题想请教。
第一个问题,memory_order_relaxed 是说 CPU 可以重新编辑指令执行顺序,那么问题来了:


针对这个函数的代码,

void push(T const& data)
{
    counted_node_ptr new_node;    // 1

    new_node.ptr = new node(data);  // 2

    new_node.external_count = 1;  // 3

    new_node.ptr->next = head.load(std::memory_order_relaxed); // 4

    while( !head.compare_exchange_weak(new_node.ptr->next,  
                                                                   new_node,
                                                                   std::memory_order_release,
                                                                   std::memory_order_relaxed) ) ;
}


4 这一行有可能在 1 2 3 之前执行吗?




第二个问题,假如一个原子变量 count,线程 A 是 store(),线程 B 是load() 操作,那么线程 A 如果指定 store(memory_order_release) ,线程 B 指定 load(memory_order_acquire),这样的话,一定是 A 的store 发生在 B 的 load() 之前吗?

我一直认为,memory-ordering 参数只影响单个线程内部的指令执行顺序,不知道会不会在线程之间对同一个变量有影响。


多谢指教。











论坛徽章:
14
水瓶座
日期:2014-06-10 09:51:0215-16赛季CBA联赛之江苏
日期:2017-11-27 11:42:3515-16赛季CBA联赛之八一
日期:2017-04-12 14:26:2815-16赛季CBA联赛之吉林
日期:2016-08-20 10:43:1215-16赛季CBA联赛之广夏
日期:2016-06-23 09:53:58程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-09 06:20:0015-16赛季CBA联赛之上海
日期:2015-12-25 16:40:3515-16赛季CBA联赛之广夏
日期:2015-12-22 09:39:36程序设计版块每日发帖之星
日期:2015-08-24 06:20:002015亚冠之德黑兰石油
日期:2015-08-07 09:57:302015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2016-11-05 19:52 |显示全部楼层
回复 1# VIP_fuck

默认的relaxed只保证atomic,而atomic是“不保证”提供memory barrier的
release,即“write release”,保证在此之前的内存操作,能够被后面的acquire(“read acquire”)后的内存操作看到

cst, “sequential consistency”,最expensive的内存操作,能够hold住SMP的bus操作,而其他barrier并没有这种限制

论坛徽章:
14
水瓶座
日期:2014-06-10 09:51:0215-16赛季CBA联赛之江苏
日期:2017-11-27 11:42:3515-16赛季CBA联赛之八一
日期:2017-04-12 14:26:2815-16赛季CBA联赛之吉林
日期:2016-08-20 10:43:1215-16赛季CBA联赛之广夏
日期:2016-06-23 09:53:58程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-09 06:20:0015-16赛季CBA联赛之上海
日期:2015-12-25 16:40:3515-16赛季CBA联赛之广夏
日期:2015-12-22 09:39:36程序设计版块每日发帖之星
日期:2015-08-24 06:20:002015亚冠之德黑兰石油
日期:2015-08-07 09:57:302015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2016-11-05 20:08 |显示全部楼层
VIP_fuck 发表于 2016-11-05 14:20
回复 2# windoze

多谢,你说的这些我知道,不过其实还是有问题想请教。

问题1:
因为存在data dependency,2和4不会reorder,除非是Alpha DEC

问题2:
不是的,“read acquire”和“write release”针对同一个变量成对的意义是:在“write release”之前的所有内存操作,都能够被“read acquire”之后的内存操作看到!
如果能够遵守这种时间顺序,那么就能够保证这种可见性。

可以看看preshing的The Synchronizes-With RelationIt’s a Runtime Relationship

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
发表于 2016-11-05 20:14 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-11-05 20:23 编辑

回复 3# VIP_fuck

问题一:  4 这一行有可能在 1 2 3 之前执行吗?
答复: 是的,  
4 这一行有可能在3 之前执行,  现代CPU都是乱序执行的, 无法确定实际执行的顺序.

第二个问题,假如一个原子变量 count,线程 A 是 store(),线程 B 是load() 操作,那么线程 A 如果指定 store(memory_order_release) ,线程 B 指定 load(memory_order_acquire),这样的话,一定是 A 的store 发生在 B 的 load() 之前吗?
答复:
A 的store 不一定是发生在 B 的 load() 之前,   
store(memory_order_release) 保证的是在此store之前的store全部执行完毕了, 线程 B 指定 load(memory_order_acquire)保证的是在此之后的load指令不允许提前执行.

我们利用这个参数实现
无锁设计方法:   memory_order_release/acquire就是对于保证struct数据的完整性, 相当于实现了读写struct的原子性的操作.
   
读线程B  
load(memory_order_acquire)  获得当前的  对象裸指针T*, 然后开始读T对象,    load(memory_order_acquire)  保证的是取到的数据一定是完整的数据, 避免发生数据乱序执行,( 避免这样的情况: 例如:先读了旧数据,再获得新的对象裸指针T*, 继续读数据, 这样一半新数据, 一半旧数据的情况 )

写线程A  新生成 一个 对象裸指针T* new,   旧对象Copy change,  
   store(memory_order_release) 更新裸指针T* ,  保证的是在此store之前的store全部执行完毕了, 保证 struct数据的完整的store了,  

当然仅仅这样还不够实现无锁并发, 还要
实现一个  垃圾内存自动回收机制, 否则部分线程读旧数据, 部分线程读新数据, 写线程如果直接回收内存, 那么部分读线程可能会崩溃或者出现离奇的错误.


论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
发表于 2016-11-05 20:31 |显示全部楼层
你看的这个范例, 应该是一个 lock_free_queue, pop部分的代码没有看到, pop部分其实是最容易出ABA错误的,  呵呵.




论坛徽章:
12
2015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之同曦
日期:2017-03-17 19:13:162016科比退役纪念章
日期:2016-11-07 08:28:12luobin
日期:2016-06-17 17:46:36wusuopu
日期:2016-06-17 17:43:4515-16赛季CBA联赛之福建
日期:2016-01-14 12:49:22程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:002015年亚洲杯之科威特
日期:2015-03-24 14:21:272015年迎新春徽章
日期:2015-03-04 09:57:092016科比退役纪念章
日期:2018-04-10 16:20:18
发表于 2016-11-06 10:06 |显示全部楼层
回复 7# wlmqgzm

pop 不是没看到,是没贴。
我先看看书。

我们的工程里绝对不会用到新标准的东西,没实践理解就不到位。

论坛徽章:
12
2015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之同曦
日期:2017-03-17 19:13:162016科比退役纪念章
日期:2016-11-07 08:28:12luobin
日期:2016-06-17 17:46:36wusuopu
日期:2016-06-17 17:43:4515-16赛季CBA联赛之福建
日期:2016-01-14 12:49:22程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:002015年亚洲杯之科威特
日期:2015-03-24 14:21:272015年迎新春徽章
日期:2015-03-04 09:57:092016科比退役纪念章
日期:2018-04-10 16:20:18
发表于 2016-11-06 10:07 |显示全部楼层
回复 5# lxyscls


感谢指教,不过有些地方还是觉得有问题,我得再把书好好看看,然后再来请教。

论坛徽章:
12
2015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之同曦
日期:2017-03-17 19:13:162016科比退役纪念章
日期:2016-11-07 08:28:12luobin
日期:2016-06-17 17:46:36wusuopu
日期:2016-06-17 17:43:4515-16赛季CBA联赛之福建
日期:2016-01-14 12:49:22程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:002015年亚洲杯之科威特
日期:2015-03-24 14:21:272015年迎新春徽章
日期:2015-03-04 09:57:092016科比退役纪念章
日期:2018-04-10 16:20:18
发表于 2016-11-06 10:25 |显示全部楼层
回复 6# wlmqgzm

你们用C++11的多线程相关的特性多吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP