..

验证

上次咱们聊到了cpu层面对于上层开发者提供的指令以及原子性实现的一些猜测。本章我们就对我们以上的猜测做一些印证。

以下截图来自于Inter手册第三卷 第八章多处理器管理

总线锁/缓存一致性协议

  • 为了内存系统上的一致性操作提供的总线锁/缓存一致性协议。

  • 为了保证系统内存一致性 当两个或多个处理器试图同时访问系统存储器中的相同地址时,必须提供一些通信机制或内存访问协议来保证数据一致性,并在某些情况下允许一个处理器暂时锁定内存位置。

  • 为了缓存一致性 当一个处理器访问缓存在另一个处理器上的数据时,它不能接收到不正确的数据。如果它修改了数据,则访问该数据的所有其他处理器都必须接收修改后的数据。这条有点类似与日常开发中分布式部署的项目有本地的map缓存及远端的Redis统一缓存。当我们修改本地缓存中的某一个数值的时候,必须保证这个修改同步到其他的节点上,否则会产生数据不一致的问题。同样的往小里看 CPU 同样是要保证这样的一致性的。必须保证多核心在操作自己缓存数据的时候在其他核心缓存上的一致性。

  • 为了允许对内存的写入按可预测的顺序进行 在某些情况下,重要的是要以与程序完全相同的顺序从外部观察内存写入。我理解的这条是保证 CPU 写入的顺序需要跟我们在程序中代码描述的顺序保持一致。比如代码中的顺序为 int a=1,b=2,c=3; 那么 CPU 需要保证在我们读取到 c=3 的时候 a=1 b=2 不会出现写重排的情况。

锁的原子操作

32位IA-32处理器支持对系统内存中位置的锁定原子操作。这些操作通常用于管理共享的数据结构(如信号量、段描述符、系统段或页表),在其中,两个或多个处理器可以同时尝试修改同一字段或标志。处理器使用三种相互依赖的机制来执行锁定的原子操作:

  • 保证原子操作。
  • 总线锁,使用LOCK#信号和LOCK指令前缀。
  • 缓存一致性协议,确保原子操作可以执行缓存数据结构(缓存锁);这种机制存在于奔腾4、Intel Xeon和P6系列处理器中。

这些机制在以下方面相互依存。某些基本内存事务(如读取或写入系统内存中的一字节)总是保证以原子方式处理。也就是说,一旦指令开始执行,处理器就保证在另一个处理器或总线访问内存位置之前,当前指令完成操作。处理器还支持总线锁定,用于执行选定的内存操作(如共享内存区域中的读取-修改-写入操作),这些操作通常需要原子处理,但不会以这种方式自动处理。因为频繁使用的内存置通常缓存在处理器的L1或L2缓存中,所以原子操作通常可以在处理器的缓存内执行,而无需总线锁。处理器的缓存一致性协议确保 当原子操作在被缓存的内存地址上执行时 其它的 缓存相同内存地址的 处理器能够被正确的管理。

Note 当发生锁竞争的情况时,软件可能需要实现算法,以确保公平获取资源以防止锁饥饿。硬件不提供任何资源保证参与代理的公平性。管理信号量的公平性和独占锁是软件的责任。

下一章我们看看Java中的具体应用