热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

RCU到底是什么?为什么快?为什么可以读写并行?

文章目录RCU经典文献RCU锁特点介绍RCU中常见问题1.有没有使用引用计数2.RCU既然没有使用引用计数,那又是确定是否存在读者引用之?3.RCU读端

文章目录

    • RCU经典文献
    • RCU锁特点介绍
    • RCU中常见问题
      • 1. 有没有使用引用计数
      • 2. RCU既然没有使用引用计数,那又是确定是否存在读者引用之?
      • 3. RCU 读端和写端同时操作,不会触发段错误吗?
      • 4. RCU 与资源回收


RCU经典文献


  • What is RCU, Fundamentally?
  • What is RCU? Part 2: Usage
  • RCU part 3: the RCU API
  • linux kernel
  • RCU作者的主页介绍

这几个连接简直就是一个宝藏,里面的干活很多很多!!!有时间一定要多看看。下文中的内容是看第一个和第二个链接的笔记和整理。直接观看原文,效果更佳。

LWN.net Logo

RCU锁特点介绍

Read-copy_update(简称RCU)技术是一种数据同步机制。常见的数据同步机制有:互斥锁,自旋锁,读写锁,顺序锁,信号量等手段。而RCU锁是一种比较高效的并发编程技术,它与2002年10月被添加到Linux内核中,在很多场景中它是用来替代读写锁的。

RCU锁的特点有:

  • 允许读写同时进行
  • 任意读;写操作时先拷贝一个副本,在副本上进行修改、发布,并在合适时间释放原来的旧数据
  • 读端不存在睡眠、阻塞、轮询,不会形成死锁,相比读写锁效率更高。

RCU也有自己的缺点:

  • 低优先级的读操作可阻塞高优先级的写操作
  • 宽限期可能比较长

这是由于RCU 写操作完毕后,会等待读端的完毕,等所有的读操作完毕后,宽限期结束,此时写端才会将资源释放。这里没有区分优先级,因此低优先级的读操作可能会影响到高优先级的写操作。

其实,RCU技术的特点还不仅如此,而有一个更重要的特点:多核扩展性。RCU虽然我们将其称之为RCU锁,但它并没有采用锁技术,而读写锁则是一个真正的锁,在扩展性上很差,设备CPU核越多,锁的竞争会越激烈,效率会越低。因此在现在很多的实现中,越来越注重无锁技术的实现。 下图是在文章What is RCU? Part 2: Usage中的一张RCU和rwlock在多核扩展性上对比图片:
请添加图片描述

RCU中常见问题


1. 有没有使用引用计数

关于RCU实现原理还有一个误解:RCU采用了引用计数的方式确定是否存在读者。 这个观点也是错的。

首先RCU并没有采用引用计数的机制,而是采用了一种非常简单的技术来实现;其次如果非要深究到底有没有引用计数,按照What is RCU? Part 2: Usage中的说法是“RCU is a Restricted Reference-Counting Mechanism”,但RCU本质上是没有采用引用计数的机制。它的解释如下:

“rcu_read_lock() 语句可以被认为是获取对 p 的引用,相当于一个引用计数。因为在 rcu_dereference() 分配给 p 之后开始的宽限期不可能在我们到达匹配的 rcu_read_unlock() 之前结束。 这种引用计数方案受到限制,因为我们不允许在 RCU 读端临界区中阻塞,也不允许我们将 RCU 读端临界区从一个任务切换到另一个任务“。

虽然有点像引用计数,但绝对不是
请添加图片描述

至于它怎么实现:检测是否有人在引用当前变量呢? 我在下面介绍下

2. RCU既然没有使用引用计数,那又是确定是否存在读者引用之?

RCU 读锁加锁和去锁最基本的函数是:

#define rcu_read_lock() preempt_disable()#define rcu_read_unlock() preempt_enable()

加锁实际上是禁止上下文切换;而解锁是允许上下文切换。它们是一个全局设置,不与任何一项锁绑定。这也是为啥RCU读锁不需要任何参数的原因。

基于此,便可以通过让CPU进行一次上下文切换来实现检测读端是否完成,而不必跟踪每一个引用的进程。 这是一个RCU非常重要的特点
请添加图片描述
进行这个操作是:synchronize_rcu(), 这个函数在内核中实现有点复杂,它毕竟还需要考虑中断,热插拔等因素。如果只考虑RCU部分,它的功能可以概括为:

第一个函数用来遍历所有的CPU;第二行run_on()函数用来将当前线程切换到指定的CPU上。如果这个任务顺利完成,则说明所有的核已经经历过一次上下文切换,此刻必定读端已经结束,否则无法触发切换。

关于这里,我曾经有一个疑问:假如最初CPU1读端结束,执行了一次上下文切换;然后在等待其他CPU过程中,又再次进入RCU读临界区,如果此时释放,会导致严重后果吗? 有点类似于下图(黄色部分表示可以进行上下文切换)
请添加图片描述
不过后来想明白了。以替换一个节点为例进行说明:

  • 链表最初状态如下:
    请添加图片描述

  • 插入一个元素时,先复制一个副本,再次基础上修改,然后完成发布
    请添加图片描述从此刻开始,rcu宽限期也开始。在发布之前的RCU读端访问的是2号节点(如果有的话),发布之后,新来的RCU读端读取的是2_new新节点。这是RCU的一个重要特点,实时性很好

    这里还没有完,旧的2号节点还没有被释放。

  • 更新操作(资源回收)

那么什么时候释放呢? 当然是所有使用2号节点的读端都完成了再释放

那么什么时候所有的读端完成呢?就是刚才提到的,synchronize_rcu()函数的任务。此函数返回后我们就可以释放了(异步释放也差不多,只不过通过回调函数来完成此项操作)

再回到刚才的问题:如果CPU都已经完成了一次上下文切换,准备进行资源释放时(例如将上面的2节点释放),其他CPU又重新进入临界区怎么办?

答案是:再次进入临界区的读端获取的是新的节点2_new, 原来的节点2已经不能再被新的读者访问到了。

这种检查原理上简单了很多,但也导致了rcu宽限期比较长。毕竟这个上下文切换是个全局设置,得照顾到所有的CPU。


3. RCU 读端和写端同时操作,不会触发段错误吗?

这个问题也是我当初百思不得其解的地方。
请添加图片描述场景:

  • 读端已经进入到1号节点
  • 写端已经复制了2号节点2_new,完成了数据更新,并且将2_new的后继指针指向了3号节点
  • 写端开始修改1号节点的后继指针,从2号节点切换到2_new节点;但是读端也正好在1号节点的后继节点,此时会出现后继节点为空导致链表遍历提前结束的情况吗?

这个问题困扰了很久。不过当我再次读What is RCU, Fundamentally?时,发现了上面有这个问题的回答。最初看时竟然没有注意到这个问题。

请添加图片描述简单的说:在Linux系统中,所有的加载和存储操都是原子的,不可能被分割。针对上述场景,读端要么读取到2节点,要么读取到2_new节点。不会出现第三结果。

4. RCU 与资源回收

请添加图片描述

最初怎么也不会将这两个联系起来。但是慢慢发现有那么一丁点像

RCU会等待资源不再被引用时释放对应的资源。从这么一点看还确实有点像GC的赶脚

不过他们最大的区别在于(从资源回收上看):程序员必须手动指定RCU读端临界区资源,甚至手动指定释放的位置。

最初怎么也不会将这两个联系起来。但是慢慢发现有那么一丁点像

RCU会等待资源不再被引用时释放对应的资源。从这么一点看还确实有点像GC的赶脚

不过他们最大的区别在于(从资源回收上看):程序员必须手动指定RCU读端临界区资源,甚至手动指定释放的位置。


推荐阅读
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 服务器上的操作系统有哪些,如何选择适合的操作系统?
    本文介绍了服务器上常见的操作系统,包括系统盘镜像、数据盘镜像和整机镜像的数量。同时,还介绍了共享镜像的限制和使用方法。此外,还提供了关于华为云服务的帮助中心,其中包括产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题和视频帮助等技术文档。对于裸金属服务器的远程登录,本文介绍了使用密钥对登录的方法,并提供了部分操作系统配置示例。最后,还提到了SUSE云耀云服务器的特点和快速搭建方法。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
author-avatar
zjy396999
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有