域名解析网站建设,wordpress文章页随机文章,怎么做培训班网站,互联网推广怎么做在非常早曾经#xff0c;大概是2009年的时候。写过一篇关于Linux RCU锁的文章《RCU锁在linux内核的演变》#xff0c;如今我承认。那个时候我尽管懂了RCU锁#xff0c;可是我没有能力用一种非常easy的描写叙述把Linux的实现给展示出来#xff0c;有道是你能给别人用你自己的… 在非常早曾经大概是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计数器为0old 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好)今天实在没有时间了要出去。兴许补充。转载于:https://www.cnblogs.com/wzjhoutai/p/7202772.html