免费注册 查看新帖 |

Chinaunix

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

娘的, 似乎犯错误了----技术帖 [复制链接]

论坛徽章:
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
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-06-27 10:39 |只看该作者 |倒序浏览
本帖最后由 zylthinking 于 2012-06-27 11:07 编辑

@塑料袋 @tempname2 @帅绝人寰 帮我看看, 搞不定了
  1. #define lock(lkp) do{  \
  2.     while(!__sync_bool_compare_and_swap(lkp, 0, 1)){    \
  3.         sched_yield();  \
  4.     }   \
  5. }while(0)

  6. #define try_lock(lkp) ({   \
  7.     (__sync_bool_compare_and_swap(lkp, 0, 1) ? 0 : -1);   \
  8. })

  9. #define unlock(lkp) do{    \
  10.     *(lkp) = 0;  \
  11. }while(0)
复制代码
lkp 在不是 volatile 的情况下, 是不是不安全?
一直以来都是这么用的, 似乎也问题, 今天突然觉得不安了
主要是 unlock 直接就是  *(lkp) = 0; 行不行?

1。 似乎不能防止编译器重拍指令, 比如

int lk = 0;
int n = 0;
lock(&lk);
++n;
unlock(&lk);

编译器有可能重排成

lock(&lk);
unlock(&lk);
++n;

2。 就算不重拍, 那么乱序呢?
执行完 unlock(&lk) 后会是怎么一种情景?
我的理解是 ++n 肯定已经执行完了, 但是可能还在 load/store unit 里面, 没有更新到寄存器
那么这个时候发生线程切换, 再次读此值, 应该会直接从 load/store unit 内直接读取到, 因此不会有太大问题; 但还是需要 @塑料袋 确认一下,
关键是如果 *(lkp) = 0; 已经进入了 load/store unit, 则可以保证 ++n 至少在 load/store unit 内, 或者已经到了寄存器中???

另外, 如果另一个线程读 n 时, 产生的汇编应该是从内存读, 那么它怎么知道内存中某单元中的值已经在 load/store unit 中了?
似乎首先要确认的是 ++n 的结果在 load/store unit 中时, 写的目标到底是存储器还是寄存器;
如果是寄存器, 也就是 n 被优化到寄存器中了, 那么CPU 还能直接从 load/store unit 中读吗? 但如果不从其中读而直接读内存, 那读出的就是一个错误的值


3。 另一个是C层面的问题了@OwnWaterloo  @starwing83  @幻の上帝

文件1:
volatile int n = 0;
文件2:
extern int n;
++n;

那么在文件2中, n 会不会还会当作 volatile 来对待
不知道会不会又是所谓 UB 行为, 但 gcc 4.2 这样做是可以的, 甚至连一个警告都没有

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
2 [报告]
发表于 2012-06-27 10:46 |只看该作者
C版有这样的帖子,才能回归理性。

论坛徽章:
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
3 [报告]
发表于 2012-06-27 10:48 |只看该作者
群雄逐鹿中原 发表于 2012-06-27 10:46
C版有这样的帖子,才能回归理性。

专家不死, 乱象不止
你要相信我

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
4 [报告]
发表于 2012-06-27 11:15 |只看该作者
3。我猜 不会当作 volatile 来对待
在不知道为 volatile 时就已经编译好了
但link时应当报错,因为 volatile int n 和 int n 不应该弄成一样的名字

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2012-06-27 11:18 |只看该作者
本帖最后由 群雄逐鹿中原 于 2012-06-27 11:19 编辑

写错,删除

论坛徽章:
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
6 [报告]
发表于 2012-06-27 11:34 |只看该作者
ARM体系的atomic.h中,更能反映锁的本质是什么。 x86的atomic.h则很难看出来。

所有不带返回值的atomic_xxx,都是__asm__ __volatile__()内原子的修改变量
所有带返回值的atomic_xxx,都是smp_mb(); __asm__ __volatile__() ; smp_mb();

获得锁的本意是 : 原子的置位锁变量; 内存屏障,用来克服乱序影响,保证对受保护数据的操作发生在置位锁变量之后。
释放锁的本意是 : 内存屏障,用来克服乱序影响,保证对受保护数据的操作发生在清零锁变量之前; 原子的清零锁变量;

kernel中只有这种带返回值的atomic_xxx可以充作锁来用,它不仅有两个smp_mb();而且有一个返回值,能判断出来是否成功的获得了锁。


至于两个文件都用了n,但只有1个说n是volatile,怎么可能另一个还认为其是volatile呢,这是不可能的。

论坛徽章:
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
7 [报告]
发表于 2012-06-27 11:37 |只看该作者
塑料袋 发表于 2012-06-27 11:34
ARM体系的atomic.h中,更能反映锁的本质是什么。 x86的atomic.h则很难看出来。

所有不带返回值的atomic_ ...


大哥, 红色的字体是我最关注的; 你要具体些啊

论坛徽章:
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
8 [报告]
发表于 2012-06-27 11:42 |只看该作者
到了load stor unit,肯定是写内存啊,写寄存器根本不过这里。

而且不管怎么乱序,CPU看自己的读写,必须是顺序的,这个是大原则。

乱序造成的主要结果,是其他CPU看本地CPU,看到的是乱序结果。

论坛徽章:
2
CU十二周年纪念徽章
日期:2013-10-24 15:41:34处女座
日期:2013-12-27 22:22:41
9 [报告]
发表于 2012-06-27 11:45 |只看该作者
回复 6# 塑料袋

为什么用户态鲜有看到这些顾虑?

乱序的CPU会打破老用户态代码的兼容性么?

除了显然的依赖外,乱序有其它constraint么?编译器的静态重排比较好接受,CPU乱序太无厘头了。



另外,@帅绝人寰表示,新闻版不开,他不再参与技术讨论

论坛徽章:
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
10 [报告]
发表于 2012-06-27 11:50 |只看该作者
塑料袋 发表于 2012-06-27 11:42
到了load stor unit,肯定是写内存啊,写寄存器根本不过这里。

而且不管怎么乱序,CPU看自己的读写,必须 ...


这才是醍醐灌顶
那么

int n = 0;
int lk = 0;

thread1:
fron 0 to 99
lock(&lk);
++n;
unlock(&lk);

thread2:

fron 0 to 99
lock(&lk);
++n;
unlock(&lk);

并不能保证 n 的终值 200 了?
因为不能避免 n 被优化到寄存器内
要保证, 必须 unlock 是一个内存栅栏才行
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP