无锁编程——从CPU缓存一致性讲到内存模型(1)
一.前言
1.什么是有锁编程,什么是无锁编程?
在编程中,特别是在并发编程的上下文中,“无锁”和“有锁”是描述线程同步和资源访问控制的两种不同策略。
有锁(Locked):
有锁编程是指使用锁(例如互斥锁、信号量等)来控制对共享资源的访问。在有锁策略中,线程必须在执行关键部分的代码前获得锁,以确保同一时间只有一个线程可以访问和修改共享资源。当线程完成对共享资源的操作后,它释放锁,使得其他线程可以接着访问资源。
特点包括:
线程安全:通过锁可以防止多个线程同时访问共享资源,避免竞争条件。
阻塞:线程在尝试获取一个已被其他线程持有的锁时,将会被阻塞,直到锁被释放。
开销:锁的获取和释放涉及操作系统层面的上下文切换,可能会导致较大的性能开销。
死锁:不正确的锁使用可能导致死锁,即两个或多个线程永久性地阻塞,等待彼此释放锁。
无锁(Lock-free):
无锁编程是一种不依赖于传统锁机制来控制共享资源访问的并发编程技术。无锁编程通常利用原子操作来确保即使在多个线程同时访问时,共享资源也能保持一致性。
那什么原子操作?
原子操作是指不可被中断的一个或一系列操作。它通过硬件支持来保证操作的原子性,通常使用特殊的CPU指令来实现。这些指令能够在单个步骤中完成读取-修改-写入的操作,而不会被其他线程中断。
上面提到的特殊指令->能够完成读取-修改-写入操作,指的是CAS(比较后交换技术)。为什么提到它,有什么用处?
这就要说到现代计算机的存储结构以及解决提升效率带来的一些硬件设备。
二.理解无锁编程需要的知识
1.存储结构

可以看出L1和L2是每个核心都会有的。L3是一个处理器下的核心共有的。
主存(常规语境下所指的内存)是所有核心共有的。
越往下容量越大,同时读取速度越慢。
Cpu访问缓存的时候会有一个最小的读取单位,叫做cache line,一般是64个字节。
那么问题来了。为什么需要cache line ?(缓存),为什么这么设计?
因为:减少内存访问延迟:CPU的运行速度远远高于主内存的访问速度。Cache Line通过提供一个小而快速的存储,使得CPU能够更快地访问经常使用的数据和指令,从而减少了因等待内存访问而造成的延迟。
提高数据访问效率:由于数据访问通常具有空间局部性(连续的数据被一起访问),Cache Line作为一个数据块单位,可以一次性将多个连续的数据加载到缓存中。这样,当CPU访问其中一个数据时,很可能接下来的数据已经在缓存中了,从而提高了数据访问的效率。
带宽优化:与内存接口相比,CPU和缓存之间的数据带宽要宽得多。通过Cache Line,可以更有效地利用这带宽,因为每次传输都是传输一个数据块,而不是单个字节。
实现预取和并行处理:现代CPU通常具有预取机制,能够预测哪些数据将会被访问,并提前将数据加载到Cache中。Cache Line作为一个块单位,使得预取更加有效。同时,多核CPU可以利用Cache Line来并行处理数据,提高多任务处理的效率。
减少总线压力:如果没有缓存,CPU每次读写数据都要直接与内存通信,这会极大地增加总线上的数据流量。Cache Line允许CPU在大多数情况下与缓存而不是内存进行通信,从而减少了总线的压力。
提升能效:由于Cache Line减少了内存访问次数,因此也降低了内存功耗,整体上提升了系统的能效。
这种由cpu写到缓存而不是内存的策略叫做写回策略。
三.写回策略
写直达策略:每次写操作会写到缓存中,也会写到内存中。写性能会很低,现代计算机很少使用了。
写回策略:尽量把数据存储到缓存之中,如果能写到缓存之中就避免写道内存中。

是否命中缓存:是指之前的缓存中是否存有这个变量。
脏数据:缓存与内存不一致,或缓存有内存无的数据被标记为脏数据。
写数据的时候如果没有命中缓存,就利用LRU策略寻找到缓存中使用最少的区域,如果这块区域有数据并且是脏数据,那么将这块区域的数据刷入内存中。如果不是直接写入缓存。
读数据的时候如果没有命中缓存,先把数据从内存读入缓存,cpu再进行使用数据。
写回策略带来什么问题?
现代计算机结构有多个核心对应多个缓存,核心间共享的变量在不同的核心的缓存里内容不一样的问题。
如何解决?
四.MESI一致性协议
通过实现MESI一致性协议解决。他的内容及流程如下:
缓存一致性协议是确保多处理器系统中各个处理器的缓存数据一致性的机制。让我们详细讨论一下最常见的MESI(Modified, Exclusive, Shared, Invalid)协议的操作流程:
1. MESI协议状态:
- Modified (M): 数据被修改,只在当前缓存中有效,与主存不一致。
- Exclusive (E): 数据只在当前缓存中,未被修改,与主存一致。
- Shared (S): 数据可能在多个缓存中存在,与主存一致。
- Invalid (I): 缓存行无效。
2. 基本操作流程:
a. 读操作:
- 缓存未命中时:
* 如果其他缓存有此数据(M或E状态),该缓存需先将数据写回主存。
* 从主存读取数据,标记为S状态(如果其他缓存也有)或E状态(如果独占)。
- 缓存命中时:
* 如果是M、E或S状态,直接读取。
* 如果是I状态,按缓存未命中处理。
b. 写操作:
- 缓存未命中时:
* 如果其他缓存有此数据,需先使其无效。
* 从主存读取数据,进行修改,标记为M状态。
- 缓存命中时:
* 如果是M状态,直接写入。
* 如果是E状态,修改并变为M状态。
* 如果是S状态,需先使其他缓存中的副本无效,然后修改并变为M状态。
* 如果是I状态,按缓存未命中处理。
3. 状态转换:
- I → E: 读取未被其他缓存持有的数据。
- I → S: 读取被其他缓存共享的数据。
- E → M: 修改独占的数据。
- S → M: 修改共享的数据(需先使其他缓存副本无效)。
- M → I, E → I, S → I: 其他处理器写入该数据。
4. 总线操作:
- Read: 请求读取数据。
- Read with Intent to Modify (RWITM): 请求读取并修改数据。
- Invalidate: 使其他缓存中的副本无效。
- Writeback: 将修改后的数据写回主存。
5. 协议执行流程:
a. 处理器发出内存访问请求。
b. 检查本地缓存状态。
c. 根据状态和操作类型,可能需要发起总线事务。
d. 其他处理器监听总线,根据需要更新自己的缓存状态。
e. 完成数据访问或修改。
上面我们提到了CAS,与缓存一致性的关系?
五.CAS
CAS:是实现原子操作和无锁数据结构的基础。
function CAS(M, A, B) isif M == AM ← Breturn trueelsereturn false
它是一种原子操作,它比较内存位置的内容与给定值,只有在相同的情况下,才会将该内存位置的内容修改为新的给定值。
CAS与缓存一致性的关系,就是需要CAS在写回策略的环境中维护正确性和高效性,这需要硬件层面的支持和软件的安全编程。
六.内存序和内存屏障
C++中原子操作往往有一个参数是规定内存序,用于指导编译器进行优化,用于指导cpu进行指令重排。可以解决两个问题,一是变量更新是否能马上被其他线程看到,二是代码顺序性的问题。
那么问题来了,为什么会有内存序问题?
因为编译器和cpu会在判断代码顺序不影响程序的情况下,有可能会重排相邻的代码执行顺序。比如一个线程锁住了一块内存空间,另一个线程无法操作那块内存空间,这项操作之后的操作并不刚需这块内存空间,这时候可能会重排先往后执行。这是为了提升整个系统的性能,但有时我们要求一定要按某个顺序执行,那么就有时候就不允许重排操作。
内存序和内存屏障是为了解决现代计算机系统中由于硬件优化和多核处理器引起的内存访问复杂性问题
内存序:指定了内存操作的可见性和顺序性规则。
内存屏障:用于强制执行特定的内存操作顺序的硬件指令。
内存序和内存屏障的关系:
- 内存序是高级抽象,定义了操作的语义。
- 内存屏障是底层实现机制,用于实现内存序。
C++11原子变量内存序的相关参数
见:std::memory_order - cppreference.com std内存屏障API,
相关文章:
无锁编程——从CPU缓存一致性讲到内存模型(1)
一.前言 1.什么是有锁编程,什么是无锁编程? 在编程中,特别是在并发编程的上下文中,“无锁”和“有锁”是描述线程同步和资源访问控制的两种不同策略。有锁(Locked): 有锁编程是指使用锁(例如互…...
C++编程(七)继承
文章目录 一、继承(一)概念(二)语法格式(三)通过子类访问父类中的成员1. 类内2. 类外 (四)继承中的特殊成员函数1. 构造函数2. 析构函数3. 拷贝构造函数4. 拷贝赋值函数 二、多重继承…...
【ACM_2023】3D Gaussian Splatting for Real-Time Radiance Field Rendering
【ACM_2023】3D Gaussian Splatting for Real-Time Radiance Field Rendering 一、前言Abstract1 INTRODUCTION2 RELATED WORK2.1 Traditional Scene Reconstruction and Rendering2.2 Neural Rendering and Radiance Fields2.3 Point-Based Rendering and Radiance Fields 3 O…...
【TB作品】atmega16 计算器,ATMEGA16单片机,Proteus仿真
实验报告:基于ATmega16单片机的简易计算器设计 1. 实验背景 计算器是日常生活和工作中不可或缺的工具,通过按键输入即可实现基本的四则运算。通过本实验,我们将利用ATmega16单片机、矩阵键盘和LCD1602显示屏,设计并实现一个简易…...
C++的IO流操作
文章目录 C语言的输入与输出流是什么CIO流C标准IO流C文件IO流二进制读写文本读写 stringstream的简单介绍 C语言的输入与输出 C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf()与printf()。 scanf(): 从标准输入设备(键盘)读取数据,并将值存放…...
MacOS升级指定Python版本的pip
场景: 系统默认是Python2.7,已经通过brew install python3.11 python3.12安装了多个版本的Python 执行:pip --version pip 24.1 from /Users/mac10.12/Library/Python/3.11/lib/python/site-packages/pip (python 3.11) 用的是Python3.11…...
音频Balance源码总结
音频Balance源码总结 何为音频Balance? 顾名思义,Balance及平衡,平衡也就是涉及多方,音频左右甚至四通道,调节所有通道的音量比,使用户在空间内听到各个通道的音频大小不一,好似置身于真实环境…...
CesiumJS【Basic】- #043 绘制脉冲线(Entity方式)- 需要自定义着色器
文章目录 绘制脉冲线(Entity方式)- 需要自定义着色器1 目标2 代码2.1 main.ts3 资源文件绘制脉冲线(Entity方式)- 需要自定义着色器 1 目标 使用Entity方式绘制脉冲线 2 代码 2.1 main.ts import * as Cesium from cesium;const viewer = new Cesium.Viewer(cesiumCont…...
Linux命令 wc(word count)-l(lines)用于统计文件中的行数。
文章目录 1、wc -l2、实战3、wc --help 1、wc -l 在命令 wc -l 中,-l 的英文全称是 lines。这个选项用于指定 wc(word count,单词计数)命令来统计文件的行数。 例如,当你运行 wc -l load_user_100w_sort.sql 时&…...
数据结构 - C/C++ - 链表
目录 结构特性 内存布局 结构样式 结构拓展 单链表 结构定义 节点关联 插入节点 删除节点 常见操作 双链表 环链表 结构容器 结构设计 结构特性 线性结构的存储方式 顺序存储 - 数组 链式存储 - 链表 线性结构的链式存储是通过任意的存储单元来存储线性…...
sheng的学习笔记-AI-高斯混合模型(GMM)
AI目录:sheng的学习笔记-AI目录-CSDN博客 需要学习前置知识: 聚类,可参考 sheng的学习笔记-AI-聚类(Clustering)-CSDN博客 EM算法,可参考 sheng的学习笔记-AI-EM算法-CSDN博客 贝叶斯,可参考 sheng的学习笔记-AI-…...
OFDM的缺点与关键技术
子载波间干扰英文简写ICI,ICI可能由各种原因引起 在多径信道中,CP小于最大附加时延时收发系统载波频率偏差和采样偏差收发系统相对移动,存在多普勒频移 ICI是制约OFDM系统性能的主要重要因素之一 对频率偏差敏感----->同步技术࿰…...
电脑录音软件哪个好?7款录制音频工具大盘点,赶快学起来!(2024)
也许你渴望提取你最喜欢的节目的背景音乐,或者你希望录制自己的声音制作教程。如果是这样,你就需要一款优秀的电脑录音软件,来帮助你捕捉任何你想要的声音,而且不会损失音质。目前市场上存在着大量的录制音频工具,面对…...
【Android面试八股文】你说你使用Leakcanary进行内存泄漏检测,那你能说一说Leakcanary的原理吗?
文章目录 一、 Java四大引用二、 LeakCanary示例工作机制注意事项三、 Leakcanary的原理四、 Leakcanary的源码分析LeakCanary#Install创建RefWatcherAndroidRefWatcherBuilder#buildAndInstall监听Activity的引用 : ActivityRefWatcher检查引用Dump Heap解析hprof定位泄露的引…...
蒂升电梯职业性格和Verify认知能力SHL测评答题攻略及薪资待遇解密!
一、蒂升电梯职业性格和认知能力测评考什么 您好!蒂升电梯公司邀请您参加的OPQ职业性格测评和Verify认知能力测评是两种常见的评估工具,用于帮助了解个人的职场性格特点和认知能力。 OPQ职业性格测评 这是一种性格测试,通常用于评估个人在…...
window上部署sql server改动端口、和sqlserver的一些还原、批量插入存储过程的命令
1.端口的查看和启动 --windows上安装上sql server数据库后,搜索界面搜索sql,会出现配置管理器,点击进入 --进入后再次选择配置管理器 2. sqlserver数据库还原图形化 sqlserver还原数据库时会使数据库进入一个restore的还原状态,…...
【单片机与嵌入式】stm32串口通信入门
一、串口通信/协议 (一)串口通信简介 串口通信是一种通过串行传输方式在电子设备之间进行数据交换的通信方式。它通常涉及两条线(一条用于发送数据,一条用于接收数据),适用于各种设备,从微控制…...
启动Redis服务器
名人说:一点浩然气,千里快哉风。 ——苏轼 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、在 Linux 或 macOS 上启动 Redis二、在 Windows 上启动 Redis三、配置 Redis 为服务启动&…...
uniapp中使用threejs加载几何体
我的建议是使用这个库 https://github.com/deepkolos/three-platformize 为什么?我试了uniapp推荐的和threejs-miniprogram这个小程序官方库,都加载不出来我的obj模型。所有我推荐不要用obj模型最好,挺多都支持GLTF模型的,但是我不…...
【SQL注入】 数据库基础
MySQL中的库名 information_schema(信息库)—— 保存其他数据库里所有信息(数据库名、表、字段的数据类型/访问权限) mysql—— 存储用户名 密码 host performance_schema——内存数据库 数据放在内存中直接操作的数据库 sys—…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...
Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...
《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...
背包问题双雄:01 背包与完全背包详解(Java 实现)
一、背包问题概述 背包问题是动态规划领域的经典问题,其核心在于如何在有限容量的背包中选择物品,使得总价值最大化。根据物品选择规则的不同,主要分为两类: 01 背包:每件物品最多选 1 次(选或不选&#…...
