【面试突击】硬件级别可见性问题面试实战(上)

🌈🌈🌈🌈🌈🌈🌈🌈
欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书
在我后台回复「面试」可领取硬核面试笔记

文章导读地址:点击查看文章导读!

感谢你的关注!

🍁🍁🍁🍁🍁🍁🍁🍁

硬件级别可见性问题面试实战

这里为什么要了解一下可见性的底层原理呢?

因为对于可见性这块的内容,他并不是软件层面上的问题,而是硬件层面的问题,是底层的一些机制导致了可见性的问题,了解了底层的相关内容之后,我们的知识会更容易形成一个闭环,而不仅仅是停留于软件层面,对下层一无所知!

所以接下来聊一聊底层中到底是什么原因导致了不同线程之间出现这个可见性的问题

可见性硬件级别造成原因

首先,每一个处理器都有自己的寄存器,而线程对变量的读操作都是针对写缓冲进行的,因此这个可见性问题与 寄存器写缓冲 这两个硬件组件是有关联的

这里分别说一下寄存器和写缓冲 如何导致了可见性的问题

  • 多个处理器都在运行各自的线程的时候,如果其中一个处理器中的线程将某一个变量更新后的值放在寄存器中,那么其他处理器中的线程是没有办法看到这个更新后的值的,因为这个寄存器是各个处理器私有的,因此,寄存器会导致可见性的问题

  • 处理器运行的线程,对变量的写操作是针对写缓冲进行的,之后才会刷到主内存中,因此如果一个线程更新了变量,如果仅仅写入到了写缓冲充,还没有刷到主内存或高速缓存中,那么其他处理器中的线程是无法感知到这个变量的修改的,此时,导致可见性的问题

    即使这个写缓冲的数据的更新也同步到了自己的主内存或高速缓存里,并且将这个更新通知给了其他的处理器,但是其他处理器可能把这个更新放到无效队列中,并没有更新自己的高速缓存,此时仍然会导致可见性的问题

如下这个图:
在这里插入图片描述

MESI 协议

那么要实现多个处理器的共享数据的一致性,可以通过 MESI 协议来实现

根据具体底层硬件的不同,MESI 协议的具体实现也是不同的

这里说一种 MESI 协议的实现:通过将其他处理器高速缓存中 更新后的数据 拿到自己的高速缓存中更新一下,这样不同处理器之间的高速缓存中的数据就保持一致了,实现了可见性

在实现 MESI 协议的过程中,需要 两个关键的机制 来确保缓存的一致性:flush 和 refresh

  • flush

将自己更新的值刷新到高速缓存里去,让其他处理器在后续可以通过一些机制从自己的高速缓存里读到更新后的值

并且还会给其他处理器发送一个 flush 消息,让其他处理器将对应的缓存行标记为无效,确保其他处理器不会读到这个变量的过时版本

  • refresh

处理器中的线程在读取一个变量的值的时候,如果发现其他处理器的线程更新了变量的值,必须从其他处理器的高速缓存(或者是主内存)里,读取这个最新的值,更新到自己的高速缓存中

因此,在底层通过 MESI 协议、flush 处理器缓存和 refresh 处理器缓存来保证可见性的

总结一下就是,flush 是强制将更新后的数据从写缓冲器中刷新到高速缓存中去;refresh 是去感知到其他处理器更新了变量,主动从主内存或其他处理器的高速缓存中加载最新数据

那么举个例子,对于 volatile 变量来说:

volatile boolean flag = true;

当写 volatile 变量时,就会通过执行一个内存屏障,在底层会触发flush处理器缓存的操作,把数据刷到主内存中

当读 volatile 变量时,也会通过执行一个内存屏障,在底层触发refresh操作,从主内存中,读取最新的值

指令重排

指令重排的内容我们可以来了解一下,什么时候会发生指令重排

指令重排指的是我们写好的代码,在真正执行的时候,执行顺序可能会被重排序,如果重排序之后,在多线程的执行环境下,可能就会出现一些问题

什么时候会发生指令重排呢?

  • 编译期间

Java 中有两种编译器,一种是静态编译器(javac),另一种是动态编译器(JIT)

javac 负责把 .java 文件中的源代码编译为 .class 文件中的字节码,这个一般是程序写好之后进行编译的

JIT 是 JVM 的一部分,负责把 .class 文件中的字节码编译为 JVM 所在操作系统支持的机器码,一般在程序运行过程中进行编译

那么在编译期间,可能编译器为了提高代码的执行效率,会对指令进行重排,JIT 对指令重排还是比较多的

  • 处理器执行顺序

编译器编译好的指令,到真正处理器执行的时候,可能还会调整顺序

指令重排有什么规则约束呢?

上边讲过了一个 happens-before 原则,它定义了一些规则,只要符合 happens-before 中的规则的都不会进行指令重排

就比如说,下边代码的第三行不可能重排到上边,因为它的执行结果依赖了上边两行的执行结果,因此不会重排,但是前两行可能会重排:

int a = 1;
int b = 2;
int c = a + b;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/416617.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React Store及store持久化的使用

1.安装 npm insatll react-redux npm install reduxjs/toolkit npm install redux-persist2. 使用React Toolkit创建counterStore并配置持久化 store/modules/counterStore.ts: import { createSlice } from reduxjs/toolkit// 定义状态类型 interface Action {…

three.js从入门到精通系列教程006 - three.js创建旋转立方体BoxGeometry

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>three.js从入门到精通系列教程006 - three.js创建旋转立方体BoxGeometry</title><script src"js/three.js"></script><script src"js/…

three.js从入门到精通系列教程007 - three.js绘制空心扇形和实心扇形

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>three.js从入门到精通系列教程007 - three.js绘制空心扇形和实心扇形</title><script src"js/three.js"></script><script src"js/jqu…

STM32之002--软件安装 Keil

文章目录&#xff1a; 一、安装 Keil 二、注册 三、安装芯片支持包 一、安装 Keil 重点 1&#xff1a; 安装时&#xff0c;不能使用中文路径&#xff0c;否则无法正常使用!! 重点 2&#xff1a; 不要安装 V5.36 及以上的版本&#xff0c;其默认AC6编译器&#xff0c…

C#,入门教程(21)——命名空间(namespace)与程序结构的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(20)——列表&#xff08;List&#xff09;的基础知识https://blog.csdn.net/beijinghorn/article/details/124094382 编写软件&#xff08;大软件称为系统&#xff09;与盖大楼一个道理。 假设咱们现在需要盖一座名为“天梯大厦”的…

UI开发布局-HarmonyOS应用UI开发布局

UI页面的构建不用再像Android开发过程中在.xml文件中书写&#xff0c;可直接在页面上使用声明式UI的方式按照布局进行排列&#xff0c;构建应用的页面。 如下代码使用Row、Column构建一个页面布局&#xff0c;在页面布局中添加组件Text、Button&#xff0c;共同构成页面&#…

VSCode OpenGL 环境搭建

目录 下载glfw、glad、安装vscode插件C/C Project Generator 下载glfw Download | GLFW 下载 glad https://glad.dav1d.de/ vscode 插件安装&#xff1a; C/C Project Generator 创建C项目&#xff1a;commondp 项目结构如下图&#xff1a; 添加glfw、glad 添加glfw 头…

ICBE 2024第十二届深圳国际跨境电商交易博览会

ICBE 2024第十二届深圳国际跨境电商交易博览会 暨中国跨境电商综试区发展高峰论坛 展会时间&#xff1a;2024年9月2日-4日 展会地点&#xff1a;深圳会展中心&#xff08;福田&#xff09; 指导单位:广东省商务厅 主办单位&#xff1a;广东省电子商务协会/扩展集团 承办单…

Kafka-RecordAccumulator分析

前面介绍过&#xff0c;KafkaProducer可以有同步和异步两种方式发送消息&#xff0c;其实两者的底层实现相同&#xff0c;都是通过异步方式实现的。 主线程调用KafkaProducer.send方法发送消息的时候&#xff0c;先将消息放到RecordAccumulator中暂存&#xff0c;然后主线程就…

C++_Lambda表达式的完整介绍

目录 1. 什么是Lambda表达式 1.1 四种表达式的含义 1.2 lambda表达式各个成员的解释 2. 捕获列表 3. 编译器如何看待Lambda表达式 参考文章 参考: C Lambda表达式的完整介绍 - 知乎 c在c11标准中引入了lambda表达式&#xff0c;一般用于定义匿名函数&#xff0c;使得代码…

【java基础】String、StringBuffer和StringBuild 那些事

String 基本特性 String是一个final类&#xff0c;代表不可变的字符序列。字符串是常量&#xff0c;用双引号引起来表示。它们的值在创建之后不能更改。String对象的字符内容是存储在一个字符数组value[]中的。 String的继承图 Serializable 在 Java 中&#xff0c;Seriali…

Electron中苹果支付 Apple Pay inAppPurchase 内购支付

正在开发中&#xff0c;开发好了&#xff0c;写一个完整详细的过程&#xff0c;保证无脑集成即可 一、先创建一个App 一般情况下&#xff0c;在你看这篇文章的时候&#xff0c;说明你已经开发的app差不多了。 但是要上架app到Mac App Store&#xff0c;则要在appstoreconnect…