无锁编程——从CPU缓存一致性讲到内存模型(1)

news2024/12/23 6:04:18

一.前言

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) is
    if M == A
        M ← B
        return true
    else
        return false

它是一种原子操作,它比较内存位置的内容与给定值,只有在相同的情况下,才会将该内存位置的内容修改为新的给定值。

CAS与缓存一致性的关系就是需要CAS在写回策略的环境中维护正确性和高效性,这需要硬件层面的支持和软件的安全编程。

六.内存序和内存屏障

C++中原子操作往往有一个参数是规定内存序,用于指导编译器进行优化,用于指导cpu进行指令重排。可以解决两个问题,一是变量更新是否能马上被其他线程看到,二是代码顺序性的问题。

那么问题来了,为什么会有内存序问题?

因为编译器和cpu会在判断代码顺序不影响程序的情况下,有可能会重排相邻的代码执行顺序。比如一个线程锁住了一块内存空间,另一个线程无法操作那块内存空间,这项操作之后的操作并不刚需这块内存空间,这时候可能会重排先往后执行。这是为了提升整个系统的性能,但有时我们要求一定要按某个顺序执行,那么就有时候就不允许重排操作。

内存序和内存屏障是为了解决现代计算机系统中由于硬件优化和多核处理器引起的内存访问复杂性问题

内存序:指定了内存操作的可见性和顺序性规则。

内存屏障:用于强制执行特定的内存操作顺序的硬件指令。

内存序和内存屏障的关系
   - 内存序是高级抽象,定义了操作的语义。
   - 内存屏障是底层实现机制,用于实现内存序。

 C++11原子变量内存序的相关参数

见:std::memory_order - cppreference.com std内存屏障API,

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis-分布式锁(基本原理和不同实现方式对比)

文章目录 1、基本原理2、不同实现方式 1、基本原理 分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行&am…

Mysql 的账户管理,索引,存储引擎

目录 一.MySQL的账户管理 1.存放用户信息的表 2.查看当前使用的用户 3.新建用户 4.修改用户名称 5.删除用户 6.修改用户密码 7.破解密码 8. 远程登录 9.用户权限管理 9.1 权限类别 9.2 查看权限 9.3 授予权限 9.4 撤销权限 二.索引 1. 索引管理 1.1 查看索…

Generating Diverse Structure for Image Inpainting With Hierarchical VQ-VAE

Jialun Peng1 Dong Liu1* Songcen Xu2 Houqiang Li1 1 University of Science and Technology of China 2 Noahs Ark Lab, Huawei Technologies Co., Ltd.pjlmail.ustc.edu.cn, {dongeliu, lihq}ustc.edu.cn, xusongcenhuawei.com 原文提供代码链接: GitHub - UST…

MySQL:数据类型

数据类型 1. 字符串类型2. 整数类型3. 定点数类型和浮点数类型4. 布尔类型5. 枚举和集合类型6. 日期和时间类型7. Blob类型8. JSON类型 字符串类型、数字类型、日期和时间类型、存放二进制的数据类型、存放地理数据的类型。 1. 字符串类型 字符串类型也可以用来存储邮编&…

【论文阅读】-- 研究时间序列可视化,提升用户体验

Investigating Time Series Visualisations to Improve the User Experience 摘要1 引言2 相关工作互动技巧视觉编码坐标系 3 用户研究时间序列可视化互动技巧任务实验设计 4 结果交互技术的效果视觉编码的影响坐标系的影响 5 讨论交互技术的效果视觉编码的影响坐标系的影响 6 …

(必看图文)Hadoop集群安装及MapReduce应用(手把手详解版)

前言 随着大数据时代的到来,处理和分析海量数据已成为企业和科研机构不可或缺的能力。Hadoop,作为开源的分布式计算平台,因其强大的数据处理能力和良好的可扩展性,成为大数据处理领域的佼佼者。本图文教程旨在帮助读者理解Hadoop集…

《昇思25天学习打卡营第5天|数据变换 Transforms》

文章目录 前言:今日所学:1. Common Transforms2. Vision Transforms3. Text Transforms 前言: 我们知道在进行神经网络训练的时候,通常要将原始数据进行一系列的数据预处理操作才会进行训练,所以MindSpore提供了不同类…

C语言部分复习笔记

1. 指针和数组 数组指针 和 指针数组 int* p1[10]; // 指针数组int (*p2)[10]; // 数组指针 因为 [] 的优先级比 * 高,p先和 [] 结合说明p是一个数组,p先和*结合说明p是一个指针 括号保证p先和*结合,说明p是一个指针变量,然后指…

蒂升电梯职业性格和Verify认知能力SHL测评答题攻略及薪资待遇解密!

​一、蒂升电梯职业性格和认知能力测评考什么 您好!蒂升电梯公司邀请您参加的OPQ职业性格测评和Verify认知能力测评是两种常见的评估工具,用于帮助了解个人的职场性格特点和认知能力。 OPQ职业性格测评 这是一种性格测试,通常用于评估个人在…

一文讲解Docker入门到精通

一、引入 1、什么是虚拟化 在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,它允许在一台物理机上创建多个独立的虚拟环境,这些环境被称为虚拟机(VM)。每个虚拟机都可以…

盘古5.0,靠什么去解最难的题?

文|周效敬 编|王一粟 当大模型的竞争开始拼落地,商业化在B端和C端都展开了自由生长。 在B端,借助云计算向千行万业扎根;在C端,通过软件App和智能终端快速迭代。 在华为,这家曾经以通信行业起…

Java登录管理功能的自我理解(尚庭公寓)

登录管理 背景知识 1. 认证方案概述 有两种常见的认证方案,分别是基于Session的认证和基于Token的认证,下面逐一进行介绍 基于Session 基于Session的认证流程如下图所示 该方案的特点 登录用户信息保存在服务端内存(Session对象&#xff…

Django 一对多关系

1,创建 Django 应用 Test/app9 django-admin startapp app9 2,注册应用 Test/Test/settings.py 3,添加应用路由 Test/Test/urls.py from django.contrib import admin from django.urls import path, includeurlpatterns [path(admin/,…

安装KB5039212更新卡在25% 或者 96% 进度

系统之家7月1日消息,微软在6月11日的补丁星期二活动中,为Windows 11系统推出了KB5039212更新。然而,部分用户在Windows社区中反映,安装过程中出现失败,进度条在25%或96%时卡住。对于遇到此类问题的Windows 11用户&…

YOLOv8改进 | 主干网络 | C2f融合动态卷积模块ODConv

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40篇内容,内含各种Head检测头、损失函数Loss、…

Linux CentOS 7 离线安装.NET环境

下载 下载.NET 例如: aspnetcore-runtime-6.0.15-linux-x64.tar.gz 复制 复制到如下目录: /usr/local/dotnet/aspnetcore-runtime-6.0.15-linux-x64.tar.gz 解压 cd /usr/local/dotnet/ tar -zxvf aspnetcore-runtime-6.0.15-linux-x64.tar.gz 创建…

非标设备行业的数智化项目管理

近年来,中国制造快速发展,企业迫切需要加快转型升级。与传统制造业相比,高端制造业具有明显的优势:高技术、高附加值、低污染、低排放、竞争优势强。一方面,企业对于生产效率和自动化水平的要求不断提高,期…

esp12实现的网络时钟校准

网络时间的获取是通过向第三方服务器发送GET请求获取并解析出来的。 在本篇博客中,网络时间的获取是一种自动的行为,当系统成功连接WiFi获取到网络天气后,系统将自动获取并解析得到时间和日期,为了减少误差每两分钟左右进行一次校…

qt可点击的QLabel

需求——问题与思路 使用wpf实现一个可点击的超链接label相当简单(如下图),但是qt的QLabel不会响应点击事件,那就从QLabel继承一个类,然后在该类中重写mousePressEvent函数,并在该函数中对左键点击事件做响…

人工智能——常用数学基础之线代中的矩阵

1. 矩阵的本质: 矩阵本质上是一种数学结构,它由按照特定规则排列的数字组成,通常被表示为一个二维数组。矩阵可以用于描述一组数据,或者表示某种关系,比如线性变换。 在人工智能中,矩阵常被用来表示数据集…