type
status
date
slug
summary
tags
category
icon
password
😀
这里写文章的前言: 一个简单的开头,简述这篇文章讨论的问题、目标、人物、背景是什么?并简述你给出的答案。
可以说说你的故事:阻碍、努力、结果成果,意外与转折。
 

📝 volatile笔记

前置条件

notion image
 
所有的数据处理都在CPU内进行,因此保存在内存中的程序在执行前需要被复制到cpu中。程序指令复制到CPU中,可以一次复制一条,也可以一次复制多条。CPU和物理内存之间的通信,CPU的处理速度远大于物理内存,所有CPU就了自己的内存,所以此时 CPU和主内存是不一致的

缓存一致性

操作系统提供

操作系统提供总线锁定的机制,前端总线(也叫CPU总线,Front Side Bus))是所有CPU与芯片组连接的主干道,负责CPU与外界所有部件的通信,包括高速缓存、内存、北桥,其控制总线向各个部件发送控制信号、通过地址总线发送地址信号指定其要访问的部件、通过数据总线双向传输。在CPU1要做 i++操作的时候,其在总线上发出一个LOCK#信号,其他处理器就不能操作缓存了该共享变量内存地址的缓存,也就是阻塞了其他CPU,使该处理器可以独享此共享内存。 但我们只需要对此共享变量的操作是原子就可以了,而总线锁定把CPU和内存的通信给锁住了,使得在锁定期间,其他处理器不能操作其他内存地址的数据,从而开销较大,所以后来的CPU都提供了缓存一致性机制,Intel的奔腾486之后就提供了这种优化。 总线锁定等颗粒度就大了,性能损失

缓存一致性

缓存一致性机制整体来说,就当某快CPU对缓存中等数据进行操作了之后,就通知其他CPU放弃存储在它们内部的缓存,或者从主线程中重新读取
 
  1. 写传播(Write Propagation): 对任何缓存中的数据的更改都必须传播到对等缓存中的其他副本(该缓存行的副本)
  1. 事务串行化:对单个内存位置的读/写必须被所有处理器以相同的顺序看到,理论上,一致性可以在加载/存储粒度上执行
  1. 一致性机制:确保一致性的两种最常见等机制是 窥探机制 和 基于目录的机制。 窥探机制:每个请求必须广播到系统中的所有节点,这意味随着系统越大,(逻辑或物理)总线大小及其宽带也必须增加。 目录机制:往往有更长的延迟(3跳 请求/转发/响应),但是使用宽带更少,因为消息都是点对点的

MESI协议

是以缓存行(缓存的基本数据单位,一般64字节)的几个状态来命名的(Modified,Exclusive,Share or Invalid)。 M: 被修改的。处于这一状态的数据,只在CPU中有缓存数据,而其他CPU中没有。同时状态相对其他内存中的值来说,是已经被修改的,且没有更新到内存中。如果别的CPU内核要读主内存这块数据,该缓存行必须写回到主存,状态修改为S E: 独占的。处于这一状态的数据,只有在本CPU中有缓存,且其数据没有修改,即与内存中一致 S: 共享的。处于这一状态的数据在多个CPU中都有缓存,且与内存一致。缓存行可以在任意时刻抛弃 I: 无效的。本CPU中的这份缓存已经无效

内存屏障

编译器和CPU在不影响结果的情况下对指令重排序,使性能得到优化,但是实际情况里面有些指令虽然没有前后依赖关系,但是重排序之后影响到输出结果,这是很插入一个 内存屏障, 相当于告诉了CPU和编译器限于这个命令的必须执行,后于这个命令的必须后执行。 内存屏障的另外一个作用是强制更新一次不同的CPU的缓存,这意味着如果你对一个volatile字段进行操作,你必须知道
  1. 一旦你完成写入,任何访问这个字段的线程将会得到最新的值
  1. 在你写入之前,会保证所有之前发生的事已经发生了,并且任何更新过的数据值也是可见的,因为内存屏障会把之前写入值都刷新到缓存

伪共享

如果多个核的线程在操作同一个缓存行中的不同变量数据,那么就出现频繁的缓存失效,即使在代码层面看这两个线程操作的数据之间完全没有关系。这在不合理的资源竞争情况就是伪共享(False Sharing)

可见性和顺序性

可见性: 每个线程操作数据的时候会把数据从主内存读取到自己的工作内存,根据MESI思想,如果某个线程修改数据写回主内存,其他线程能通过嗅探检测到本地数据无效,然后从主内存读取到自己的工作内存 顺序性:通过指令间加入内存屏障来防止指令重排序

嗅探

每个处理器通过嗅探在总线上传播的数据来检测自己的缓存数据是不是过期了,当处理器发现自己缓存数据对应的内存地址被修改,就会将当前处理器的缓存数据设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存
 

总线风暴

java中使用unsafe实现cas,而其底层有C++调用汇编指令实现的,如果多核cpu使用lock cmpxchg,单核cpu使用cmpxch指令 如果在段时间内产生大量的cas操作再加上volatile的嗅探机制则会不断地占用总线宽带,导致总线流量激增,就会产生总线风暴

🤗 总结归纳

📎 参考文章

 
💡
有关文章的问题,欢迎您在底部评论区留言,一起交流~