作者Arton0306 (Ar藤)
看板C_and_CPP
标题[问题] thread会将值存在register中不写回?
时间Sun Oct 14 18:45:59 2018
这个问题是出自"程式设计师的自我修养"这一本书
里面28页陈述了一个问题
x = 0;
Thread1 Thread2
lock(); lock();
x++; x++;
unlock(); unlock();
书上说可能thread1做完x++时,这个x=1的值还留在register中还没写回,
之後换thread2跑完,很久之後thread1才把此值写回,最後x的值是1
但书上这个例子看起来就是一般multithread用mutex锁住一段code的写法,
目前也没看过这种写法发生错误
请问这个情况什麽时候会发生?
还是说平常在用的unlock会自动把register中的值flush出去?
我把28页照片放上来
https://photos.app.goo.gl/QYG5LffdJLUC9PfA8
(特别查了一下着作权法,放个一页应该是没什麽问题@@)
着作权法第五十二条规定:「
为报导、评论、教学、研究或其他正当目的之必要,在合理范围内,
得引用已公开发表之着作。」
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 36.227.78.148
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1539513961.A.CDA.html
1F:推 stupid0319: 看不太懂,x应该是同一块记忆体,怎会有flush的问题 10/14 19:10
2F:→ Lipraxde: 恩...应该 compiler 优化有问题才会像你说的这样啊?有 10/14 20:14
3F:→ Lipraxde: 没有前後文? 10/14 20:14
4F:→ descent: 他後面有提到 volatile 和 memory barrier, page 29 10/14 20:30
※ 编辑: Arton0306 (36.227.78.148), 10/14/2018 20:36:06
5F:→ Arton0306: 我说flush是指写出去到memory的意思 10/14 20:38
6F:→ Arton0306: 29页那个cpu自行换序的问题 我试过真的会发生 10/14 20:40
7F:→ Arton0306: 但28页这个我没遇过 10/14 20:40
8F:→ Arton0306: 再看一次 好像真的如同L大说的 这段是在讲compiler的问 10/14 20:46
9F:→ Arton0306: 题 所以compiler看到mutex夹住的要小心 应该是这意思@@ 10/14 20:48
10F:→ Arton0306: 我原本以为它是说code有问题 冏XD 10/14 20:54
11F:→ stupid0319: 如果是留在暂存器中,也不能算做完x++吧 10/14 21:33
12F:→ stupid0319: 书上意指lock前就把x值存进暂存器? 10/14 21:38
我想它这段真的是没有写很清楚,以下是我的理解:
它说「落後的编译器技术已经无法满足日益增长的并行需求,很多看似无错的程式码
在最佳化和并行面前又产生了麻烦,最简单的例子…(就是我上面写的code)」
也就是它举了一个compiler最佳化出bug的例子,
在它的例子中
x+1的值留在register中,不是lock前就存进暂存器,
而是因为有可能之後会再用到,这样比较快
singlethread是可以这麽做,
但在multithread的情况下,这样的最佳化是compiler的bug
而它28页最下方和29页的例子是code真的有问题 compiler不可能解决
2个例子摆在一起容易误会
※ 编辑: Arton0306 (36.227.78.148), 10/14/2018 23:09:24
13F:→ stupid0319: 唉,连记忆体到CPU暂存器的时间也要省 10/14 23:38
14F:推 Bencrie: 存取暂存器的时间远小於记忆体啊 XD 10/15 01:19
15F:→ PkmX: 现在的C/C++有规范不同thread之间的memory model 10/15 02:18
16F:→ PkmX: 以std::mutex来说 unlock "synchronizes-with"下一个lock 10/15 02:28
17F:→ PkmX: unlock前的side effects必须让lock後的code看到 10/15 02:28
18F:→ PkmX: 如果编译器没有把x的值写回记忆体的话就是做错了 10/15 02:28
19F:推 steve1012: c++ 11以後要follow sequential consistency. 10/15 13:05
感谢 原来後来加进standard了
想到一段以前写过的code
bool isStop = false; // global var
thread 1 thread 2
while (!isStop) { do something...
do something isStop = true
}
也就是thread1 重复做某件事 直到thread2设定了isStop的flag
例如用在gui取消/中断某个耗时的计算
现在回想起来
isStop没有用lock包起来是否有问题??
如果加上volatile 而没有lock 这样是否安全?
※ 编辑: Arton0306 (36.227.78.148), 10/16/2018 01:59:34
20F:→ PkmX: seq_cst是atomic operation之间预设才有 10/16 09:44
21F:→ PkmX: 像上面那种bool isStop两个threads同时写还是UB 10/16 09:44
22F:→ PkmX: 除非你有用mutex等东西让两个读写有"happens-before"的关系 10/16 09:45
23F:推 jun0325: 用volatile应该就会让compiler每次都会写回memory了吧 10/16 22:12
24F:→ PkmX: 照标准volatile和thread之间的synchronization是没有关系的 10/17 10:47
25F:→ PkmX: 而且volatile也不一定是atomic access 10/17 10:48
我发现我原本写的thread 1的while (isStop)写错了
改了while (!isStop) 才对
我上面的例子只有2个thread,只有thread2才会去写isStop
※ 编辑: Arton0306 (220.136.4.208), 12/07/2018 01:38:57