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. 数据库锁包括:读锁(可共享锁)和 ...
随机推荐
- HDU——2602Bone Collector(01背包)
Bone Collector Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- [OJ#15]TR #2 画心
[OJ#15]TR #2 画心 试题描述 渠是一名画师.渠有一支神奇的画笔,可以画尽因果. 渠要画一幅画,这幅画由N个线段组成,线段从1开始编号,第i条线段有一个特殊的因果值Ai. 由于画太长了,渠不 ...
- 算法复习——扫描线(hdu1542)
题目: Problem Description There are several ancient Greek texts that contain descriptions of the fable ...
- leetcode 20 简单括号匹配
栈的运用 class Solution { public: bool isValid(string s) { stack<char>The_Stack; ; The_Stack.push( ...
- Failed to apply plugin [id 'com.gradle.build-scan']
把spring源码clone下来之后,使用gradle编译不通过,异常日志如下: FAILURE: Build failed with an exception. * Where: Build fil ...
- 两个时间相差多少 .net中的timespan应用
原文发布时间为:2008-10-31 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...
- 简单说明PHP的垃圾收集机制是怎样的?【转】
原文链接: https://www.cnblogs.com/gengyi/p/6372020.html?utm_source=itdadao&utm_medium=referral. 对变 ...
- Codeforces 558E A Simple Task(权值线段树)
题目链接 A Simple Task 题意 给出一个小写字母序列和若干操作.每个操作为对给定区间进行升序排序或降序排序. 考虑权值线段树. 建立26棵权值线段树.每次操作的时候先把26棵线段树上的 ...
- CMDB与自动化运维,一切尽在掌握中?
生产力跟不上生产的速度时,就会出现很多问题,如何针对问题进行处理,制定什么样的计划,如何解决就是需要思考的难点? T运维的分类 IT运维,指的是对已经搭建好的网络,软件,硬件进行维护.运维领域也是细分 ...
- ionic build Android错误记录 error in opening zip file
0.写在前头 运行 :cordova requirements Requirements check results for android: Java JDK: installed 1.8.0 An ...