Linux内核RCU(Read Copy Update)锁简析
在非常早曾经,大概是2009年的时候。写过一篇关于Linux RCU锁的文章《RCU锁在linux内核的演变》,如今我承认。那个时候我尽管懂了RCU锁,可是我没有能力用一种非常easy的描写叙述把Linux的实现给展示出来,有道是你能给别人用你自己的方式非常简洁地描写叙述清楚,你才是真正的精通它。否则,无异于背诵。换个说法,假设你在被面试。在短时间内靠嘴说给面试官,且他还要能听明白,就说明自己真的懂了,这样的时候,是不会给你机会分析源码的,也不可能让你背诵源码。
时隔五年多,最近又碰到了这个话题,我不能自诩自己对RCU锁是多么精通,可是起码,和2009年相比,我确实有所进步,因此在这个台风肆虐的次日,我尝试着用我自己的方式描写叙述一下Linux对RCU锁的一种实现方式,作为《RCU锁在linux内核的演变》这篇文章的补充。本文不配图,没代码,仅仅是文字。
声明:假设你还不知道RCU锁是什么。请自行baidu,本文不再赘述概念。可是这也就等于说,假设我自己有一天忘记了RCU。我也不能指望从本文中得到不论什么帮助。我总是这样,不是吗?能力在忘不在记。得其义而忘其形。
RCU要素
RCU锁的要素包含
读标志
假设一个Reader企图占领一把RCU锁,它是不须要付出不论什么代价的,仅仅须要设置一个标志,让外界知道有Reader在占领这把RCU锁。多个Reader能够共同持有一把RCU锁。
写时拷贝
假设有一个Write企图更新RCU锁所保护的数据,那么它会首先查看该RCU锁的读标志,假设有该标志,说明有最少一个Reader持有了该RCU锁。它须要对原始数据make a copy,写这个副本并将更新过的副本保存在某处,等待时机用该副本更新原始数据。
更新时机
这个时机就是用副本更新原始数据的时间点。这个时间点怎样确定是RCU锁实现的算法核心,它直接能够确定全部的数据结构。确切来讲,Writer必须waitting for all readers leaving,方可Update原始数据,问题是,它是怎么知道全部的Reader都离开了呢?
Linux内核对RCU锁的几种实现
1.原始实现-利用抢占禁止
Linux内核于2.6内核引入了RCU锁的概念。在第一个版本号中,它利用了抢占禁止的方式来标志有Reader持有RCU锁,这意味着期间不能发生task切换(指的是task_struct所代表的sched entity切换)。
那么全部Reader均已经释放RCU锁的标志就是。task切换了,因此非常easy,用副本Update原始数据的时机就是task切换时。
全部的Write会将自己写的副本挂在一个list上,在task切换的时候会touch这个list,假设该list非空,则遍历每个元素。Update原始数据。
评价[该部分与实现无关,纯形而上的,能够忽略]
这就是第一版的原始实现。它是否合理姑且不论。确实。它能够工作。可是:
a.它这样的实现是否会影响调度子系统的时延
b.因为禁用抢占,抢占粒度变粗,对交互性是否会有影响
c.对CPU间的task负载均衡的影响呢
我们发现,因为RCU的这个实现不是靠自身机制实现的,它不可避免地会影响到系统的核心机制。比方调度,负载均衡等,这意味着它不能长久。也无法经历复杂的演变。因为随着它在这条路上的逐步演进,对系统核心机制的影响将越来越大,故而,它必须从系统层面剥离出来。确实,它也是这么做的。这就是第二代RCU实现-可抢占RCU锁。
2.新实现-利用阶段计数器
须要一种更加有效的方式来标志Reader已经持有锁-第一要素读标志,而且这个标志要尽可能精确,且不能使用系统核心的机制,要做成全然封闭的闭环,不依靠外部当然也就不会影响外部。
纯天然的想法就是使用计数器,每一把RCU持有一个Reader计数器,一旦有Reader前来持锁。仅仅须要一个原子操作,将该计数器加1就可以,Writer写数据时。发现计数器不是0就意味着须要make a copy了-第二要素写时拷贝(COW-Copy On Write)。
如今的问题是第三要素,Writer怎么知道全部的Reade都已经将锁释放了呢??
纯天然的想法就是在某个Reader释放锁的时候,计数器减1。当计数器又一次变为0的时候。这就是副本更新原始数据的时机。
确实是这样,可是依照持锁和解锁的分布看,它们应该是均等的,这意味着计数器的值会在一个期望值上下波动,变成0的希望及其渺茫,因此须要引入还有一个參量,即阶段。
将唯一的那个RCU计数器分裂为两个计数器:old readers和new readers。
太初,任选某一个时刻,将RCU锁当前的计数器(称为原始计数器)值复制一份存入old readers,计数器清0,原始计数器改称为new readers。复制结束的当下,new readers计数器为0,old readers计数器为现阶段持有锁的reader的数量。而且持锁者task(即task_struct)与RCU锁之间保持关联(难道不是一个task_struct字段能够搞定的吗?)。task永远知道自己是new reader还是old reader。
此时,就能够明白定义lock和unlock的行为了:
lock--设置自己的task为new reader,将RCU的new reader计数器加1。
unlock--获取自己的task是new reader还是old reader,将自己所在的reader计数器减1。
此时非常明白的事实是。old reader计数器总是会递减而不会递增,而new reader不但会递增也会递减。这样,选择Update的时机也非常明白了,那就是,old reader计数器变为0,这个时刻,就该将全部的副本覆盖原始数据了。
如今总结全部的三个要素:
读标志
为该RCU锁的new reader计数器加1
写时拷贝
假设该RCU锁的old reader计数器不为0,则运行写时复制。
更新时机
每次unlock操作,都会将本task的reader计数器(或者是new reader。或者是old reader)减1。一旦该RCU锁的old reader计数器变成0。则运行全部的Update操作。
评价[该部分与实现无关,纯形而上的。能够忽略]
持有RCU锁的reader。能够睡眠,能够被抢占。能够调度到别的CPU上,全然是封闭的,和系统其他的机制无关。
然而。我一直在思考一个更好的实现,仅仅因疯子不给力。!
3.RCU Tree实现(实在是没有2好)
今天实在没有时间了,要出去。兴许补充。
Linux内核RCU(Read Copy Update)锁简析的更多相关文章
- Linux 内核:匠心独运之无锁环形队列kfifo
Linux 内核:匠心独运之无锁环形队列 Kernel version Linux 2.6.12 Author Toney Email vip_13031075266@163.com Da ...
- linux 内核 RCU机制详解
RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制读取数 ...
- linux内核 RCU机制详解【转】
本文转载自:https://blog.csdn.net/xabc3000/article/details/15335131 简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前 ...
- linux 内核的另一个自旋锁 - 读写锁
除spinlock外,linux 内核还有一个自旋锁,名为arch_rwlock_t.它的头文件是qrwlock.h,包含在spinlock.h,头文件中对它全称为"Queue read/w ...
- linux物理页面的换入换出简析
2017-04-25 我们都知道,现代操作系统使用分页机制和虚拟内存,同时为了提高物理页面的利用率,采用了请求调页的机制,即物理内存的分配只有在真正需要的时候才会进行,比如发生了真正的读写操作,而普通 ...
- Linux中 /proc/[pid] 目录各文件简析
Linux 内核提供了一种通过 proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc 文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文件系统的方式为访问系 ...
- Linux内核的同步机制---自旋锁
自旋锁的思考:http://bbs.chinaunix.net/thread-2333160-1-1.html 近期在看宋宝华的<设备驱动开发具体解释>第二版.看到自旋锁的部分,有些疑惑. ...
- mysql innodb锁简析(2)
继续昨天的innodb锁的分析: 注:此博文参考一下地址,那里讲的也很详细.http://xm-king.iteye.com/blog/770721 mysql事务的隔离级别分为四种,隔离级别越高,数 ...
- mysql innodb锁简析(1)
说好的每天一个技术博客,选了iteye,但是,那个界面真的好丑啊,丑的让我都没写下去的欲望了,所以,还是转移到博客园里面吧,虽然这里也是很丑的! 直接步入正题: 1. 数据库锁包括:读锁(可共享锁)和 ...
随机推荐
- 深入浅出mysql全文随笔
进入mysql :mysql -uroot -p 1.DDL(Data Definition Languages)语句:数据定义语言 2.DML(Data Manipulation Language) ...
- jenkins+maven+testng参数化执行测试用例
碰到一个场景是,在做自动化中,一个系统往往需要兼容很多浏览器,如何在一个工程中,通过参数化去启动不同的浏览器,而无需改动配置文件呢? 我解决的思路是: 1.通过jenkins的参数传递给maven 2 ...
- 需要打印真实尺寸大小等需求的,css的单位可以使用mm等做单位
今天甲方那边改需求了,要求打印出来的尺寸是85mm/55mm的,开始还一直在网上找px和mm的相关换算,结果去w3c看了,竟然还有mm单位的, 在这里做个笔记
- 【CF1017B】The Bits(模拟)
题意:给定两个二进制数字a,b,可以任意交换a中的两个bit位,求进行这样一次操作,最多可产生多少种不同的a or b n<=1e5 思路:模拟,分类讨论 #include<cstdio& ...
- SQL注入原理及防范
1.1.2 正文 SQL Injection:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令. 具体来说,它是利用现有应用程序,将(恶 ...
- iOS上实现圆角图片
UIImageView自带 //圆角设置 imageView.layer.cornerRadius = ;(值越大,角就越圆) imageView.layer.masksToBounds = YES; ...
- 正确使用‘trap指令’实现Docker优雅退出
一般应用(比如mariadb)都会有一个退出命令,用户使用类似systemctl stop ****.service方法,停止其服务时,systemd会调用其配置文件注册的退出命令,该命令执行清理资源 ...
- hdu 1588(矩阵好题+递归求解等比数列)
Gauss Fibonacci Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- LeetCode OJ-- Reverse Integer
https://oj.leetcode.com/problems/reverse-integer/ 一个整数,给反过来,比如123输出321.注意12300的情况,应该输出321,还有-123,是-3 ...
- 关于Red5整合springMVC提示scope not found 的错误
https://www.cnblogs.com/qgc88: