RCU-机制

RCU(Read-Copy Update)主要针对的数据对象是链表,目的是提高遍历读取数据的效率,使用RCU机制读取数据的时候不对链表进行耗时的加锁操作。这样在同一时间可以有多个线程同时读取该链表,并且允许一个线程对链表进行修改(修改的时候,需要加锁)。RCU适用于需要频繁的读取数据,而相应修改数据并不多的情景,例如在文件系统中,经常需要查找定位目录,而对目录的修改相对来说并不多,这就是RCU发挥作用的最佳场景

特点:

1. 同时允许多读,一写线程                     # 适用读多写少的场景。

实现原理:

1. 在写操作,copy一份链表数据更新

2. 等宽限期到,更新数据指针到新的链表数据

基本操作:

reader:

1. rcu_read_lock  标识RCU read side临界区的开始

2. rcu_dereference 获取数据指针

3. rcu_read_unlock 标识RCU read side临界区结束

writer:

1.  rcu_assign_pointer 更新数据指针  # 在witer完成新版本数据分配和更新之后

2. synchronize_rcu 宽限期,等待原链表数据上的reader 线程完成后,进行删除旧链表


----------------------------------转载---------------------------------

原文链接:RCU机制

前言

       本来想继续顺着数据包的处理流程分析upcall调用的,但是发现在分析upcall调用时必须先了解linux中内核和用户空间通信接口Netlink机制,所以就一直耽搁了对upcall的分析。如果对openVswitch有些了解的话,你会发现其实openVswitch是在linux系统上运行的,因为openVswitch中有很多的机制,模块等都是直接调用linux内核的。比如:现在要分析的RCU锁机制、upcall调用、以及一些结构体的定义都是直接从linux内核中获取的。所以如果你在查看源代码的一些结构(或者模块,机制性代码)时,发现在openVswitch中没有定义(我用的是Source Insight来查看和分析源码,可以很好的查看是否定义过),那么很可能就是openVswitch包含了linux头文件引用了linux内核的一些定义。

        RCU是linux的新型锁机制(RCU是在linux 2.6内核版本中开始正式使用的),本来一直纠结要不要用篇blog来说下这个锁机制。因为在openVswitch中有很多的地方用到了RCU锁,我开始分析的时候都是用一种锁机制一笔带过(可以看下openVswitch(OVS)源代码分析之数据结构里面有很多地方都用到了RCU锁机制)。后来发现有很多地方还用到了该锁机制的链表插入和删除操作,而且后面分析的代码中也有RCU的出现,所以就稍微的说下这个锁机制的一些特性和操作。

RCU运行原理        

        我们先来回忆下读写锁(rwlock)运行机制,这样可以分析RCU的时候可以对照着分析。读写锁分为读锁(也称共享锁),写锁(也称排他锁,或者独占锁)。分情况来分析下读写锁:

        第一、要操作的数据区被上了读锁;1、若请求是读数据时,上读锁,多个读锁不排斥(即,在访问数据的读者上线未达到时,可以对该数据区再上读锁);2、若请求是写数据,则不能马上上写锁,而是要等到数据区的所有锁(包括读锁和写锁)都释放掉后才能开始上写访问。

        第二、要操作的数据区上了写锁;则不管是什么请求都必须等待数据区的写锁释放掉后才能上锁访问。

        同理来分析下RCU锁机制: RCU是read copy udate的缩写,按照单词意思就知道这是一种针对数据的读、复制、修改的保护锁机制。锁机制原理:

        第一、写数据的时候,不需要像读写锁那样等待所有锁的释放。而是会拷贝一份数据区的副本,然后在副本中修改,等待修改完后。用这个副本替换原来的数据区,替换的时候就要像读写锁中上写锁那样,等到原数据区上所有访问者都退出后,才进行数据的替换;根据这种特性可以推断出,用RCU锁可以有多个写者,拷贝了多份数据区数据,修改后各个写着陆续的替换掉原数据区内容。

        第二、读数据的时候,不需要上任何锁,也几乎不需要什么等待(读写锁中如果数据区有写锁则要等待)就可以直接访问数据。为什么说几乎不需要等待呢?因为写数据中替换原数据时,只要修改个指针就可以,消耗的时间可以说几乎不算,所以说读数据不需要其他额外开销。

        总结下RCU锁机制特性,允许多个读者和多个写者同时访问共享数据区的内容。而且这种锁对多读少写的数据来说是非常高效的,可以让CPU减少些额外的开销。如果写得操作多了的话,这种机制就没读写锁那么好了。因为RCU写数据开销还是很大的,要拷贝数据,然后还要修改,最后还要等待替换。其实这个机制就好比我们在一台共享服务器上放了个文件,有很多个人一起使用。如果你只是看看这个文件内容,那么直接在服务器上cat查看就可以。但如果你要修改该文件,那么你不能直接在服务器上修改,因为你这样操作会影响到将要看这个文件或者写这个文件的人。所以你只能先拷贝到自己本机上修改,当最后确认保证正确时,然后就替换掉服务器上的原数据。

RCU写者工作图示    

      下面看下RUC机制下修改数据(以链表为例)


        根据上面的图会发现其实替换的时候只要修改下指针就可以,原数据区内容在被替换后,默认会被垃圾回收机制回收掉。

linux内核RCU机制API

        了解了RCU的这些机制原理,下面来看下linux内核中常使用的一些和RCU锁有关的操作。注意,本blog并不会过多的去深究RCU最底层的实现机制,因为分享RCU工作机制的目的只是为了更好的了解openVswitch中使用到的那部分代码的理解,而不是为了分析linux内核源代码,不要本末倒置。如果遇到个知识点就拼命的深挖,那么你看一份源代码估计得几个月。

        rcu_read_lock();看到这里有人可能会觉得和上面有矛盾,不是说好的读者不需要锁吗?其实这不是和上读写锁的那种上锁,这仅仅只是标识了临界区的开始位置。表明在临界区内不能阻塞和休眠,也不能让写者进行数据的替换(其实这功能远不止这些)。rcu _read_unlock()则是和上面rcu_read_lock()对应的,用来界定一个临界区(就是要用锁保护起来的数据区)。

        synchronize_rcu();当该函数被一个CPU调用时(一般是有写者替换数据时调用),而其他的CPU都在RCU保护的临界区读数据,那么synchronize_rcu()将会保证阻塞写者,直到所有其它读数据的CPU都退出临界区时,才中止阻塞,让写着开始替换数据。该函数作用就是保证在替换数据前,所有读数据的CPU能够安全的退出临界区。同样,还有个call_rcu()函数功能也是类似的。如果call_rcu()被一个CPU调用,而其他的CPU都在RCU保护的临界区内读数据,相应的RCU回调的调用将被推迟到其他读临界区数据的CPU全部安全退出后才执行(可以看linux内核源文件的注释,在Rcupdate.h文件中rcu_read_look()函数前面的注释)。 

        rcu_dereference(); 获取在一个RCU保护的指针,指向RCU读端临界区。他的指针以后可能会被安全地解除引用。说到底就是一个RCU保护指针。

        list_add_rcu();往RCU保护的数据结构中添加一个数据节点进去。这个和一般的往链表中增加一个节点操作是类似的,唯一不同的是多了这条代码:rcu_assign_pointer(prev->next, new); 代码大概含义:分配指向一个新初始化的结构指针,将由RCU读端临界区被解除引用,返回指定的值。(说实话我也不太懂这个注释是什么意思)大概的解释下:就是让插入点的前一个节点的next指向新增加的new节点,为什么要单独用一条这个语句来实现,而不是用 prev->next = new;直接实现呢?这是因为prev->next本来是指向其他值得,有可能有CPU通过prev->next去访问其他RCU保护的数据了,所以如果你要插入一个RCU保护的数据结构中必要要调用这个语句,它里面会帮你处理好一些细节(比如有其他CPU使用后面的数据,直接使用prev->next可能会使读数据的CPU断开,产生问题),并且让刚加入的新节点也受到RCU的保护。这类的插入有很多,比如从头部插入,从尾 部插入等,实现都差不多,这里不一一细讲。

         list_for_each_entry_rcu();这是个遍历RCU链表的操作,和一般的链表遍历差不多。不同点就是必须要进入RCU保护的CPU(即:调用了rcu_read_lock()函数的CPU)才能调用这个操作,可以和其他CPU共同遍历这个RCU链表。以此相同的还有其他变相的遍历及哈希链表的遍历,不细讲。

        如果在openVswitch源代码分析中发现了有关RCU的分析和这里的矛盾,可以以这里为准,当然我也会校对下

————————————————

版权声明:本文为CSDN博主「庾志辉」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/YuZhiHui_No1/article/details/40115559

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容