【计算机体系结构】缓存的false sharing
在介绍缓存的false sharing之前,本文先介绍一下多核系统中缓存一致性是如何维护的。
目前主流的多核系统中的缓存一致性协议是MESI协议及其衍生协议。
MESI协议
MESI协议的4种状态
MESI协议有4种状态。MESI是4种状态的首字母缩写,缓存行的4种状态分别如下。
(1)修改(Modified):表示数据只在本处理器的缓存中存在副本,数据是脏的,即数据被修改过,没有写回到内存。
(2)独占(Exclusive):表示数据只在本处理器的缓存中存在副本,数据是干净的,即副本和内存中的数据相同。
(3)共享(Shared):表示数据可能在多个处理器的缓存中存在副本,数据是干净的,即所有副本和内存中的数据相同。
(4)无效(Invalid):表示缓存行中没有存放数据。
MESI协议的消息
为了维护缓存一致性,处理器之间需要通信,MESI协议提供了以下消息。
(1)读(Read):包含想要读取的缓存行的物理地址。
(2)读响应(Read Response):包含读消息请求的数据。读响应消息可能是由内存控制器发送的,也可能是由其他处理器的缓存发送的。如果一个处理器的缓存有想要的数据,并且处于修改状态,那么必须发送读响应消息。
(3)使无效(Invalidate):包含想要删除的缓存行的物理地址。所有其他处理器必须从缓存中删除对应的数据,并且发送使无效确认消息来应答。
(4)使无效确认(Invalidate Acknowledge):处理器收到使无效消息,必须从缓存中删除对应的数据,并且发送使无效确认消息来应答。
(5)读并且使无效(Read Invalidate):包含想要读取的缓存行的物理地址,同时要求从其他缓存中删除数据。它是读消息和使无效消息的组合,需要接收者发送读响应消息和使无效确认消息。
(6)写回(Writeback):包含想要写回到内存的地址和数据。
MESI协议的状态转换
缓存行状态的转换如下图所示。

(1)转换a,修改M到独占E:处理器收到写回消息,把缓存行写回内存,但是缓存行保留数据。
(2)转换b,独占E到修改M:处理器写数据到缓存行。
(3)转换c,修改M到无效I:处理器收到“读并且使无效”消息,发送读响应消息和使无效确认消息,删除本地副本(不需要写回内存,因为发送“读并且使无效”消息的处理器需要写数据)。
(4)转换d,无效I到修改M:处理器写不在本地缓存中的数据,发送“读并且使无效”消息,通过读响应消息收到数据。处理器可以在收到所有其他处理器的使无效确认消息以后转换到修改状态M。
(5)转换e,共享S到修改M:处理器写数据,该数据在缓存中命中,则只需发送使无效消息,收到所有其他处理器的使无效确认消息以后转换到修改状态M。
(6)转换f,修改M到共享S:其他处理器读取缓存行,发送读消息,本处理器收到读消息后,写回内存,保留一个只读副本,发送读响应消息。
(7)转换g,独占E到共享S:其他处理器读取缓存行,发送读消息,本处理器收到后发送读响应消息,保留一个只读副本。
(8)转换h,共享S到独占E:本处理器意识到很快需要写数据,发送使无效消息,收到所有其他处理器的使无效确认消息以后转换到独占状态E。
(9)转换i,独占E到无效I:其他处理器写数据,发送“读并且使无效”消息,本处理器收到消息后,发送读响应消息和使无效确认消息。
(10)转换j,无效I到独占E:处理器写不在本地缓存中的数据,发送“读并且使无效”消息,收到读响应消息和所有其他处理器的使无效确认消息后转换到独占状态E,完成写操作后转换到修改状态M。
(11)转换k,无效I到共享S:处理器加载不在本地缓存中的数据,发送读消息,收到读响应消息后转换到共享状态S。
(12)转换l,共享S到无效I:其他处理器写本地缓存中的数据,发送使无效消息,本处理器收到后,把缓存行的状态转换为无效,发送使无效确认消息。
false sharing伪共享
false sharing概念
定义:当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。
Cache和内存之间交换数据的最小粒度不是字节,而是称为cache line的一块固定大小的区域,缓存行是内存交换的实际单位。缓存行是2的整数幂个连续字节,一般为32~256个字节,最常见的缓存行大小是64个字节。
在写多线程代码时,为了避免使用锁,通常会采用这样的数据结构:根据线程的数目,安排一个数组, 每个线程一个项,互相不冲突。从逻辑上看这样的设计无懈可击,但是实践的过程可能会发现有些场景下非但没提高执行速度,反而性能会很差。
问题在于cpu的Cache Line,当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享,即false-sharing。
例如,在Intel Core 2 Duo处理器平台上,L2 cache是由两个core共享的,而L1 data cache是分开的,由两个core分别存取。cache line的大小是64 Bytes。假设有个全局共享结构体变量f由2个线程A和B共享读写,该结构体一共8个字节同时位于同一条cache line上。
struct foo {int x;int y;
};
若此时两个线程一个读取f.x另一个读取f.y,即便两个线程的执行是在独立的cpu core上的,实际上结构体对象f被分別读入到两个CPUs的cache line中且该cache line 处于shared状态。若此时在核心1上运行的线程A想更新变量X,同时核心2上的线程B想要更新变量Y,则:
如果核心1上线程A优先获得了所有权,线程A修改f.x会使该CPU core 1上的这条cache line将变为modified状态,另一个CPU core 2上对应的cache line将变成invalid状态;此时若线程B马上读取f.y,为了确保cache一致性,B所在CPU核上的相应cache line的数据必须被更新;当核心2上线程B优先获得了所有权然后执行更新操作,核心1就要使自己对应的缓存行失效。这会来来回回的经过L3缓存,影响性能。如果互相竞争的核心位于不同的插槽,就要额外横跨插槽连接,若读写的次数频繁,将增大cache miss的次数,严重影响系统性能。
虽然在memory的角度这两种访问是隔离的,但是由于错误的紧凑地放在了一起,使得两个变量处于同一个缓存行中。每个线程都要去竞争缓存行的所有权来更新变量。可见,false sharing会导致多核处理器上对于缓存行Cache Line的写竞争,造成严重的系统性能下降,有人将伪共享描述成无声的性能杀手,因为从代码中很难看清楚是否会出现伪共享。
false-sharing避免方法
把每个项凑齐Cache Line的长度,即可实现隔离,虽然这不可避免的会浪费一些内存。
- 对于共享数组而言,增大数组元素的间隔使得由不同线程存取的数组元素位于不同的Cache Line上,使一个核上的Cache line修改不会影响其它核;或者在每个线程中创建全局数组的本地拷贝,然后执行结束后再写回全局数组,此方法比较粗暴不优雅。
- 对于共享结构体而言,使每个结构体成员变量按照Cache Line大小(一般64B)对齐。可能需要使用#pragma宏。
相关文章:
【计算机体系结构】缓存的false sharing
在介绍缓存的false sharing之前,本文先介绍一下多核系统中缓存一致性是如何维护的。 目前主流的多核系统中的缓存一致性协议是MESI协议及其衍生协议。 MESI协议 MESI协议的4种状态 MESI协议有4种状态。MESI是4种状态的首字母缩写,缓存行的4种状态分别…...
Ubuntu24.04 Isaacgym的安装
官方论坛 rl-接口 教程1 教程2 教程3 1.下载压缩包 link 2. 解压 tar -xvf IsaacGym_Preview_4_Package.tar.gz核心教程在 isaacgym/docs/install.html下 3. 从源码安装 Ubuntu24.04还需首先进入虚拟环境 python -m venv myenv # 创建虚拟环境,已有可跳过…...
docker 设置代理,通过代理服务器拉取镜像
docker 拉取目标镜像需要通过代理服务器进行时,可以通过为 docker 配置全局代理来实现。 注:Linux 上通过临时命令 export HTTP_PROXY 设置的代理,对 curl 这些有用,但是对 docker pull 不起作用。 示例 假设您的代理服务器地址是…...
OpenCV教程02:图像处理系统1.0(翻转+形态学+滤波+缩放+旋转)
-------------OpenCV教程集合------------- Python教程99:一起来初识OpenCV(一个跨平台的计算机视觉库) OpenCV教程01:图像的操作(读取显示保存属性获取和修改像素值) OpenCV教程02:图像处理…...
人工智能在招投标领域的运用---监控视频连续性检测
作者:舒城县公共交易中心 zhu_min726126.com 原创,转载请注明出处。 摘要 随着人工智能(AI)技术的飞速发展,其在各个领域的应用日益广泛。本文旨在探讨人工智能在招投标领域的运营,重点介绍AI对视频完整…...
加装德国进口高精度主轴 智能手机壳「高质量高效率」钻孔铣槽
在当前高度智能化的社会背景下,智能手机早已成为人们生活、工作的必备品,智能手机壳作市场需求量巨大。智能手机壳的加工过程涉及多个环节,包括钻孔和铣槽等。钻孔要求精度高、孔位准确,而铣槽则需要保证槽位规整、深度适宜。这些…...
Java Stream API 常用操作技巧
Java 8 引入的 Stream API 为集合操作提供了一种声明式编程模型,极大地简化了数据处理的复杂性。本文将介绍 Java Stream API 的几种常用操作方式,帮助开发者更高效地处理集合数据。 1. 过滤(Filtering) 过滤是选择集合中满足特…...
SwiftData 模型对象的多个实例在 SwiftUI 中不能及时同步的解决
概览 我们已经知道,用 CoreData 在背后默默支持的 SwiftUI 视图在使用 @FetchRequest 来查询托管对象集合时,若查询结果中的托管对象在别处被改变将不会在 FetchedResults 中得到及时的刷新。 那么这一“囧境”在 SwiftData 里是否也会“卷土重来”呢?空说无益,就让我们在…...
Android 系统网络、时间服务器配置修改
1.修改wifi 是否可用的检测地址: 由于编译的源码用的是谷歌的检测url,国内访问不了,系统会认为wifi网络受限,所以改成国内的地址 adb shell settings delete global captive_portal_https_urladb shell settings delete global captive_por…...
类和对象深入理解
目录 static成员概念静态成员变量面试题补充代码1代码2代码3如何访问private中的成员变量 静态成员函数静态成员函数没有this指针 特性 友元友元函数友元类 内部类特性1特性2 匿名对象拷贝对象时的一些编译器优化 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接…...
在postgres数据库中的几个简单用法
1、例如表中coord_str的字段数据是121.12334 31.3435这样的字符串,如何将对应的数据转换成geometry数据,实现如下 UPDATE coordinates SET geom ST_GeomFromText(POINT( || split_part(coord_str, , 1) || || split_part(coord_str, , 2) || ), 43…...
SQLServer Manager Studio扩展开发从入门到弃坑
Visualstudio的已经开发好了,可这个就是不行,直接运行点这些按钮加载失败,而我直接不调试模式,则直接什么都没有,调试 发现是根本没触发逻辑的。 文档资料太少, 我换了几个ssms.exe都不行,18-20…...
ComfyUI预处理器ControlNet简单介绍与使用(附件工作流)
简介 ControlNet 是一个很强的插件,提供了很多种图片的控制方式,有的可以控制画面的结构,有的可以控制人物的姿势,还有的可以控制图片的画风,这对于提高AI绘画的质量特别有用。接下来就演示几种热门常用的控制方式 1…...
【篇三】在vue3上实现阿里云oss文件直传
之前写了两篇关于文件上传的文章 【篇一】使用springbootvue实现阿里云oss上传 【篇二】使用springbootvue实现阿里云oss文件直传,解决大文件分片上传问题 今天介绍一下在vue3中实现阿里云oss文件直传,主要是基于篇二中的源码进行修改,看具体…...
OceanBase v4.2 特性解析:对Json与Xml的扩展支持
1. 背景 OceanBase的Oracle模式当前已实现对XMLType类型的支持,不仅包含了基本的构造、查询、更新以及格式转换功能,还支持使用Xpath查询从XML数据中提取特定值。在V 4.2.2 版本中,我们进一步扩展了Oracle模式下对XMLType的支持,…...
《框架封装 · 统一异常处理和返回值包装》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...
深入WebKit:揭秘复杂文档的高效渲染之道
深入WebKit:揭秘复杂文档的高效渲染之道 在当今信息爆炸的时代,网页不再仅仅是简单的文本和图片的集合,而是充满了复杂布局和丰富媒体内容的交互式平台。WebKit 作为众多流行浏览器的心脏,其布局引擎承担着将 HTML、CSS 代码转换…...
进程的控制-孤儿进程和僵尸进程
孤儿进程 : 一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被 init 进程( 进程号为 1) 所收养,并由 init 进程对它们完成状态收集工作 为了释放子进程的占用的系统资源: …...
【Unity navigation面板】
【Unity navigation面板】 Unity的Navigation面板是一个集成在Unity编辑器中的界面,它允许开发者对导航网格(NavMesh)进行配置和管理。 Unity Navigation面板的一些关键特性和功能: 导航网格代理(NavMesh Agent&…...
二刷算法训练营Day53 | 动态规划(14/17)
目录 详细布置: 1. 392. 判断子序列 2. 115. 不同的子序列 详细布置: 1. 392. 判断子序列 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
