百科问答小站 logo
百科问答小站 font logo



当两个CPU核心要求读写同一内存地址时,其后果是未定义行为吗? 第1页

  

user avatar   bei-ji-85 网友的相关建议: 
      

题主是想问的是CPU核间怎么同步数据吧。先说x86架构下的实现:

早期的Intel CPU(SkyLake)内部有一个高速环形总线:

环形总线的频率等于CPU的主频(最高标称主频,不含睿频),多核间的数据同步就是通过这个环形总线完成的,新一点的CPU的总线设计有变化,改成网状设计的。

一个核心对内存的操作,不加锁(LOCK前缀)的情况下,需要20-50个cycle(指令周期)才能反应到另外一个核心上。

所以

       CPU0:MOV EAX,number CPU1:MOV number,EAX     

两个核心上的EAX并不是你的期望值。

当多个核心同时写一个地址时:

       CPU0:MOV number,EAX CPU1:MOV number,EAX     

并不存在同时写的情况,只是写到当前核心的L1 cache上,再经过20-50个cycle同步到其它核心,广播cache刷新的动作是由环形总线的仲裁机制实现的,目前CPU厂商没有公布具体的仲裁原理,一般来说,只有一个核心的写入动作会成功广播出去,另外一个核心的写操作会被丢弃。

到真实的硬件场景中,你很难做到同时写入,因为不同核心的工作频率可能都是不一样的、指令可能是乱序执行的。

相对于题主说的“未定义”,我更倾向于使用“不确定”来描述这种行为。

如果加了锁(LOCK),那么多核会依次执行对应的指令:

       CPU0: LOCK ADD sum,EAX CPU1: LOCK ADD sum,EAX     

sum会最终加上两次EAX(注意每个核都有自己的EAX)。遇到LOCK指令时,CPU核心会通过环形总线通告其它核心要锁定的总线地址,如果其它核心需要修改对应的地址,就会停下来等待。LOCK前缀通常需要20个cycle才能完成总线的锁定,而一般的MOV指令,则是3-4个cycle左右(内存作为操作数)。

所以上面的这个例子,在Intel的CPU上,需要几十个cycle才能完成。


以上都是硬件层面的例子,一个设计正确的软件,需要使用锁、原子变量等操作来保护多线程编程条件下的数据正确性,这是由程序员自己实现的,如果不使用正确的同步机制,代码的实际运行结果可能不满足期望值


对于非x86架构来说,锁的机制可能完全不同,CPU的乱序方式也不完全一样,甚至很多在x86上工作正常的代码(主要是驱动一类的代码),到了ARM上运行结果就不一样,所以,不加锁的情况下,对同一块内存的访问,不同的硬件结果可能不一样。


user avatar   haozhi-yang-41 网友的相关建议: 
      

这问题有意思:

首先,不要学了个ub,就到处拿着ub去套。CPU本质上就是个物理电路,它的一切行为都是由物理定律保证的,不可能有什么ub——哪怕CPU有设计失误,那也是bug,而不是ub。

然后,大多数主流的CPU不会直接对内存进行存取操作(极低端的单片机还有,但那些不可能有多核),都必须是把内存数据加载到缓存中进行访问和操作的。所以,你的问题实际上就转换为另一个业内更标准的问题表述:缓存一致性问题。

接着,多CPU为了解决这个缓存一致性问题,会使用MESI或类似机制(具体自己搜自己学)。这些机制保证了必然只有一个CPU的cache是有效的,其他的则必须放弃cache中的数据并且重新从内存中加载。

最后,LOCK的问题则完全不同。LOCK是明确需要锁总线或者cache line的,很多还默认带有mb的含义。所以,如果连汇编层面的LOCK都保证不了逻辑语义的话,那没有任何上层软件可以保证得了。


user avatar   pansz 网友的相关建议: 
      

独立缓存往公共缓存的操作是串行的,不会同时发生。

然后应该没有了,毕竟你一定要过缓存的,不可能直接读写内存。

实际上在计算机领域,绝大多数同时发生的事情最终在指令集层面都会变成串行发生。例如键盘同时按下两个键,由于键盘实际上是周期扫描每个键是否按下然后上报。扫描每个键的时间点不同,所以即便每个键精确的同时按下,最后上报的次序也有先后。

多请求同时操作单个实体的情况下,就算请求有多个来源,往往也是轮询每个来源的请求,然后逐个执行,最终依然还是串行。所以独立缓存往公共缓存读写数据最终也会变成串行操作。

绝大多数情况下,你不用担心指令集层面的并行问题,这是硬件设计会避免的。你只需要考虑软件设计的逻辑层面的并行问题。




  

相关话题

  现在主存的速度已经超过CPU的速度,那么CPU片内的cache是否可以取消? 
  可以预先将 X86 平台机器码译码到 micro operations 来解决 X86 译码效率低吗? 
  为什么 CPU 主频很难超过 4GHz? 
  为什么系统调用时要把一些寄存器保存到内核栈又从内核栈恢复? 
  手机性能提高10倍以后,会有什么改变? 
  为什么英特尔酷睿 CPU 已经做到了 12 代,但很多人的笔记本电脑仍在使用 5 代或更早的处理器? 
  年薪到手30万+,却舍不得给自己配一台台式机,是不是很可悲? 
  2017 年 AMD 要翻身了吗? 
  高通SDM660AIE与联发科P60的差别? 
  电脑死机的时候电脑在干什么? 

前一个讨论
Windows C++如何直接写分区表?
下一个讨论
为什么本人笔记本使用 Linux 和 Windows 编译速度完全不一样?(尤其是arduino)?





© 2024-11-21 - tinynew.org. All Rights Reserved.
© 2024-11-21 - tinynew.org. 保留所有权利