Linux内核--第五篇博客--RCU机制及内存优化屏蔽

一、RCU机制

RCU 英文全称为 Read-Copy-Update ,顾名思义就是 “读 - 拷贝 -更新”,是内核中重要 的同步机制。 Linux内核已有原子操作、读写信号量等等锁机制,为何会单独设计一个比较复杂的新机制?

1RCU原理

RCU记录所有指向共享数据的指针的使用者,当要修改该共享数据时,首先创建一个 副本,在副本中修改。所有读访问线程都离开读临界区之后 ,指针指向新的修改后副本的指针,并且删除旧数据。

2、链表操作

RCU 能保护的不仅仅是一般的指针。内核也提供标准函数,使得能通过 RCU机制保护 双链表,这是 RCU 机制在内核内部最重要的应用。
有关通过 RCU保护的链表,好消息是仍然可以使用标准的链表元素。只有在遍历链表、 修改和删除链表元素时,必须调用标准函数的 RCU变体。函数名称很容易记住:在标准函数之后附加 _rcu 后缀。
RCU 标准:内核源码分析: /include/linux/rculist.h
static inline void list_add_rcu(struct list_head *new, struct list_head *head)
static inline void list_add_tail_rcu(struct list_head *new,struct list_head *head)
static inline void list_del_rcu(struct list_head *entry)
static inline void list_replace_rcu(struct list_head *old,struct list_head *new)
 
a 、读拷贝更新( RCU )模式添加链表项
内核源码分析: /include/linux/rculist.h

b 、读拷贝更新( RCU )模式删除链表项
内核源码分析: /include/linux/rculist.h
c 、读拷贝更新( RCU )模式更新链表项
内核源码分析: /include/linux/rculist.h

3、RCU层次架构

RCU 根据 CPU 数量的大小按照树形结构来组成其层次结构,称为 RCUHierarchy
内核源码分析: /kernel/rcu/tree.h

二、优化内存屏障

1、优化屏障

在编程时,指令一般不按照源程序顺序执行,原因是为提高程序执行性能,会对它进行优化,主要为两种:编译器优化和 CPU 执行优化。
优化屏障避免编译的重新排序优化操作,保证编译程序时在优化屏障之前的指令不会在优化屏障之后执行。
Linux 使用宏 barrier 实现优化屏障,如 gcc 编译器的优化屏障宏定义如:

2、内存屏障

内存屏障,也称内存栅障或屏障指令等,是一类同步屏障指令,是编译器或 CPU对内存访问操作的时候,严格按照一定顺序来执行,也就是 memory barrier 之前的指令和memory barrier 之后的指令不会由于系统优化等原因而导致乱序。
memorybarrier 包括两类:编译器屏障( complierbarrier )和 CPU 屏障( cpubarrier
 
1.RCU写者修改对象的过程是:首先复制生成一个副本,然后更新这个副本,最后使用新的对象替换旧的对象。在写者执行复制更新的时候读者可以读数据。
 
2.写者删除对象,必须等到所有被访问被删除对象的读者访问结束,才能够执行销毁操作。RCU关键技术是怎么判断所有读者已经完成访问。等待所有读者访问结束的时间称为宽限期。(grace period)。
 
3、RCU读者并不需要直接与写者进行同步,读者与写者也能并发的执行。RCU目标最大程度来减少读者的开销。因为也经常用于读者性能要求高的场景。
 
4、RCU优点:读者开销少,不需要获取任何锁,不需要执行原子指令或内存屏蔽;没有死锁问题;没有优先级反转的问题;
没有内存泄漏的危险问题;很好的实时延迟操作。
 
5、RCU缺点:写者的同步开销比较大的,写者之间需要互斥处理;比使用其它同步机制复杂。
 
6、RCU应用场景
例如: 每种锁都有自己适合场景: spin lock 不区分reader/writer, 对于些读写强度不对称的是不合适的,RW spin lock 和seq lock解决了这个问题,seq lock倾向writer,RW spin lock倾向reader。
a、RCU只能保护动态分配的数据结构,并且必须是通过指针访问该数据结构;
b、受RCU保护的临界区不能sleep;
c、读写不对称,对writer的性能没有特别的需求,但是reader性能要求极高;
d、reader端对新旧数据不敏感。
RCU适用于需要频繁的读取数据,而相应修改数据并不多的场景。比如:文件系统中,搜索定位目录,而对目录修改相对来讲基本没有。
 
7、链表操作
 
 
将新的链表元素new添加到表头为head的链表头部,而list_add_tail将其添加到链表尾部
 
 

从链表删除链表元素entry。

将链表元素old换为new

----------------------------------------------------------------------------------------------------------------------------

对于writer,RCU操作包含:

1、rcu_assign_pointer: 该函数被用来进行removal的操作,在writer完成新版数据分配和更新之后,调用这个函数可以记RCU protected pointer 指向 protected data。

2、synchronize_rcu: writer 端操作可以是同步的,也就是说,完成更新操作之后,可以调用这个函数等待所有旧版本数据上的reader线程离开临界区,一旦从函数返回,说明旧的共享数据没有任何的引用,直接进行recla mationdd的操作。

3、call_rcu: writer无法阻塞,这时候可以调用call_rcu接口函数,该函数是注册callback直接返回,在适当机会调用callback函数,完成recla mation的操作。

removal:write分配一个new version 共享数据进行数据更新,更新完之后将rcu protected pointer 指向新版本数据,一旦把RCU protected pointer 指向的新的数据,也就意味着将推向前台。通过这样的操作,原来reader0,reader1对共享数据的引用被删除,它们都在旧版本的rcu protected data上进行数据访问。

reclamation: 共享数据不能有两个版本,因此一定要在适当的时机回收旧版的数据。

----------------------------------------------------------------------------------------------------------------------------


----------------------------------------------------------------------------------------------------------------------------

 
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值