atomic是原子的意思,意味"不可分割"的整体。在Linux kernel中有一类atomic操作API。这些操作对用户而言是原子执行的,在一个CPU上执行过程中,不会被其他CPU打断。最常见的操作是原子读改写,简称RMW。例如,atomic_inc()接口。atomic硬件实现和Cache到底有什么关系呢?其实有一点关系,下面会一步步揭晓答案。

问题背景

我们先来看看不使用原子操作的时候,我们会遇到什么问题。我们知道increase一个变量,CPU微观指令级别分成3步操作。1) 先read变量的值到CPU内存寄存器;2) 对寄存器的值递增;3) 将寄存器的值写回变量。例如不使用原子指令的情况下在多个CPU上执行以下increase函数。

int counter = 0;

void increase(void)

{

counter++;

}

例如2个CPU得系统,初始值counter为0。在两个CPU上同时执行以上increase函数。可能出现如下操作序列:

+ +----------------------+----------------------+

| | CPU0 operation | CPU1 operation |

| +----------------------+----------------------+

| | read counter (== 0) | |

| +----------------------+----------------------+

| | increase | read counter (== 0) |

| +----------------------+----------------------+

| | write counter (== 1) | increase |

| +----------------------+----------------------+

| | | write counter (== 1) |

| +----------------------+----------------------+

V

timeline

我们可以清晰地看到,当CPU0读取counter的值位0后,在执行increase操作的同时,CPU1也读取counter变量,同样counter的值依然是0。随后CPU0和CPU1先后将1的值写入内存。实际上,我们想执行两次increase操作,我应该得到counter值为2。但是实际上得到的是1。这不是我们想要的结果。为了解决这个问题,硬件引入原子自增指令。保证CPU0递增原子变量counter之间,不被其他CPU执行自增指令导致不想要的结果。硬件是如何实现原子操作期间不被打断呢?

Bus Lock

当CPU发出一个原子操作时,可以先锁住Bus(总线)。这样就可以防止其他CPU的内存操作。等原子操作结束,释放Bus。这样后续的内存操作就可以进行。这个方法可以实现原子操作,但是锁住Bus会导致后续无关内存操作都不能继续。实际上,我们只关心我们操作的地址数据。只要我们操作的地址锁住即可,而其他无关的地址数据访问依然可以继续。所以我们引入另一种解决方法。

Cacheline Lock

为了实现多核Cache一致性,现在的硬件基本采用MESI协议(或者MESI变种)维护一致性。因此我们可以借助多核Cache一致性协议MESI实现原子操作。我们知道Cache line的状态处于Exclusive或者Modified时,可以说明该变量只有当前CPU私有Cache缓存了该数据。所以我们可以直接修改Cache line即可更新数据。并且MESI协议可以帮我们保证互斥。当然这不能不能保证RMW操作期间不被打断,因此我们还需要做些手脚实现原子操作。

我们依然假设只有2个CPU的系统。当CPU0试图执行原子递增操作时。a) CPU0发出"Read Invalidate"消息,其他CPU将原子变量所在的缓存无效,并从Cache返回数据。CPU0将Cache line置成Exclusive状态。然后将该cache line标记locked。b) 然后CPU0读取原子变量,修改,最后写入cache line。c) 将cache line置位unlocked。

在步骤a)和c)之间,如果其他CPU(例如CPU1)尝试执行一个原子递增操作,CPU1会发送一个"Read Invalidate"消息,CPU0收到消息后,检查对应的cache line的状态是locked,暂时不回复消息(CPU1会一直等待CPU0回复Invalidate Acknowledge消息)。直到cache line变成unlocked。这样就可以实现原子操作。我们称这种方式为锁cache line。这种实现方式必须要求操作的变量位于一个cache line。

LL/SC

LL/SC(Load-Link/Store-Conditional)是另一种硬件实现方法。例如aarch64架构就采用这种方法。这种方法就不是我们关注的重点了。略过。

总结

借助多核Cache一致性协议可以很方便实现原子操作。当然远不止上面举例说的atomic_inc还有很多其他类似的原子操作,例如原子比较交换等。

atomic原子类实现机制_atomic实现原理相关推荐

  1. atomic原子类实现机制_JUC学习笔记--Atomic原子类

    Atomic 原子操作类包 Atomic包 主要是在多线程环境下,无锁的进行原子操作.核心操作是基于UnSafe类实现的CAS方法 CAS CAS: compareAndSwap :传入两个值:期望值 ...

  2. atomic原子类实现机制_深入了解Java atomic原子类的使用方法和原理

    在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...

  3. atomic原子类实现机制_并发编程:并发操作原子类Atomic以及CAS的ABA问题

    本文基于JDK1.8 Atomic原子类 原子类是具有原子操作特征的类. 原子类存在于java.util.concurrent.atmic包下. 根据操作的数据类型,原子类可以分为以下几类. 基本类型 ...

  4. (转)Java atomic原子类的使用方法和原理(一)

    在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...

  5. atomic原子类实现机制_JDK中Atomic开头的原子类实现原子性的原理是什么?

    JDK Atomic开头的类,是通过 CAS 原理解决并发情况下原子性问题. CAS 包含 3 个参数,CAS(V, E, N).V 表示需要更新的变量,E 表示变量当前期望值,N 表示更新为的值.只 ...

  6. atomic原子类实现机制_Java并发包-atomic包-让您彻底掌握AtomicInteger源码

    从这一篇文章开始,我开始对并发包的atomic包进行源码解析,首先通过下面的图了解以下atomic包中的类都是有哪些? atomic包中的所有类 这一篇文章首先对AtomicInteger进行讲解.在 ...

  7. atomic原子类实现机制_反射机制实现两个类的复制

    废话不多说 简单的实现 直接上代码 我怕话多审核不过 实现的类 public class Copy {@SneakyThrowspublic static void objectClone(Objec ...

  8. Atomic原子类及原理

    目录 1 前言 2 unsafe类对Atomic原子类的支持 3 AtomicInteger的内部实现 3.1 准备 3.2 读 3.3 写 4 CAS机制 4.1 基本操作数 4.2 例子 4.3 ...

  9. 「死磕Java并发编程」说说Java Atomic 原子类的实现原理

    <死磕 Java 并发编程>系列连载中,大家可以关注一波. 「死磕 Java 并发编程」阿里二面,面试官:说说 Java CAS 原理? 「死磕 Java 并发编程」面试官:说说什么是 J ...

  10. JUC多线程:Atomic原子类与CAS原理

    一.Atomic 原子类的原理: Atomic 原子操作类是基于无锁 CAS + volatile 实现的,并且类中的所有方法都使用 final 修饰,进一步保证线程安全.而 CAS 算法的具体实现方 ...

最新文章

  1. 《CLR Via C# 第3版》笔记之(十五) - 接口
  2. pytorch 优化GPU显存占用,避免out of memory
  3. 基数排序算法图解分析
  4. 读书笔记_CLR.via.c#第十六章_数组
  5. plsql中导入csvs_在命令行中使用sql分析csvs
  6. cesium label 显示隐藏到地底下
  7. 计算机应用与基础实践怎么考,自考计算机基础应用科目笔试和实践性考试怎么考...
  8. django mongodb mysql,Django MongoDB Django NoSQL方案
  9. python字符串和字节串有什么区别_python – 字符串和字节字符串之间的区别是什么?...
  10. css之px自动转rem—“懒人”必备
  11. 跟着鬼哥学爬虫-2-糗事百科
  12. Java数据持久层框架
  13. 2019通信工程师最新的职业发展方向
  14. 微软Win11与万物互联时代新系统需求更加迫切
  15. mysql 全文索引 (N-gram parser)
  16. 数据分析师岗位 分析可视化
  17. HTML设置格式化时间
  18. 拼多多java后台笔试题目总结(20180830)
  19. 【翻译】 Intel(R) 800 Series序列网卡 ice 驱动安装
  20. Google Earth Engine(GEE)——GEE版本的全球森林火灾信息获取并呈现2001-2020年四川省火灾亮度时间序列分析

热门文章

  1. 【游戏开发引擎】 实验3:Captain Blaster 2D 滚动射击游戏
  2. 01-Lambert 漫反射
  3. DNS服务(二):域名劫持
  4. 股票10档接口如何获取数据-步骤
  5. python中sys模块是干什么的_python中sys模块的介绍和使用
  6. [Maven实战-许晓斌]-[第二章]-2.3安装目录分析
  7. 计算机类专业哪些专业比较好,计算机类专业有哪些 哪个专业比较好
  8. Microsoft-Yahoo: Not Again. Why Again?
  9. js将数字金额用符号间隔 vue中使用逗号间隔数字金额-共享博客
  10. [Mac] 为mac自带的QuickTime Player播放器设置快进快退