- 主题:乱序执行的CPU怎么处理多线程中,共享变量有前后依赖的问题的?
【 在 wjhtingerx 的大作中提到: 】
: 比如:
: 线程1:
: b=2;
: ...................
乱序当然会发生,线程1如果改成:
d = b
b = 2
a = 1,
那么a= 1更可能先执行,线程2的程序c=b当然会执行,只不过一般后果无所谓所以你看不到啥后果。
如果a=1的时候c只能被赋值为2否则系统就爆炸,那只要运行事件够长这种逻辑运行次数够多,你一定能看到系统爆炸。
爆炸一次,你就会想办法通过互斥信号量,原子操作,读写同步(ARM上就是DMB/DSB/ISB)等指令来保证逻辑正确。
最简单的, b=2后面增加dsb指令,确保数据写执行完成以后系统才能执行后面的数据操作。
--
修改:beanspower FROM 111.197.20.*
FROM 111.197.20.*
【 在 wjhtingerx 的大作中提到: 】
: 为啥增加d = b后,a更容易乱序?
: 我的疑问是,这种场景应该是很多的,但是实际开发中,知道这些的程序员其实很少的,为啥也没听说爆出啥大的问题呢
:
知道这个点不多是因为你的岗位接触的少。
如果你是一个嵌入式工程师,写过最简单的NOR FLASH驱动,就一定会遇到这种严格要求执行结果的case。因为一旦乱序,硬件就不work了。所以驱动代码中插入了很多barrier指令。
其他场景也很多,不一而足。写应用程序代码的一般不需要这个知识点。你写驱动代码或者操作系统内核代码就会时不时遇到。Linux里面有标准的read/write/read&write的barrier接口API。
增加d = b后更容易乱序是因为前面对b的操作更多需要更多的指令,既然需要更多的指令,系统在执行这些指令的时候就更容易对后面的指令乱序执行(等不及了,因为多流水线多发射的系统有空闲资源了)。
ARM里的dsb指令就是data sync barrier,保证之前的指令中和数据相关的指令都一定完成才会执行dsb后面和数据相关的指令。
所以就是我之前帖子里说的,你这个case,在b=2后面增加一个dsb,ARM系统里绝对就没问题了。
本中是做CPU架构研究和OS内核适配的,对这些浸淫已久....
--
修改:beanspower FROM 111.197.20.*
FROM 111.197.20.*
【 在 wjhtingerx 的大作中提到: 】
: 这里回答很多是错的,volatile只约束编译结果,跟CPU的乱序执行无关。
:
这里chatGPT只提到了java应用层面的volatile,它说了能那估计就能了。因为编译器应该是在和这个指令后面增加了barrier指令。C的volatile是达不到这个效果的,必须自己显式的增加barrier指令。
不管是c,java还是c++,最底层的逻辑是一样的,都是同样的处理器架构和汇编要求。
--
FROM 111.197.20.*
【 在 wjhtingerx 的大作中提到: 】
: 为啥增加d = b后,a更容易乱序?
: 我的疑问是,这种场景应该是很多的,但是实际开发中,知道这些的程序员其实很少的,为啥也没听说爆出啥大的问题呢
:
另外,你不是在另一个帖子问以太网的问题吗。你看看以太网驱动,在最后设置descriptor的状态之前,一定有一个显式的barrier指令,就是为了解决乱序问题。,确保数据就绪才能设置“硬件发送”标志。
--
FROM 111.197.20.*
【 在 wjhtingerx 的大作中提到: 】
: 问题这个场景不仅限于驱动或底层,在多线程数据传递共享方面,场景大量存在。我就没看过有谁注意到这个事,都是随便写,因为知道这个的就没几个人。但实际呢,我也没遇到过因为这个事导致的问题,我也干嵌入式软件快20年了,感觉挺奇怪的
:
:
这个场景是造出来的,为了说明多线程乱序的情况。大多数情况下没有这个问题。或者,有问题的场景别人都趟平了。
这一定是个问题,你没遇到说明就是没有或者后果不严重呗。我说过了,如果结果不对系统就爆炸,那你的系统一定会爆炸。
--
FROM 111.197.20.*