RCU机制
RCU英文全称为Read-Copy-Update,顾名思义就是 “读 – 拷贝-更新”,是内核中重要的同步机制。
RCU原理
RCU记录所有指向共享数据的指针的使用者,当要修改该共享数据时,首先创建一个副本,在副本中修改。所有读访问线程都离开读临界区之后 ,指针指向新的修改后副本的指针,并且删除旧数据。
更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.
Linux内核源码/内存调优/文件系统/进程管理/设备驱动/**协议栈-学习视频教程-腾讯课堂
链表操作
RCU能保护的不仅仅是一般的指针。内核也提供标准函数,使得能通过RCU机制保护 双链表,这是RCU机制在内核内部最重要的应用。
//添加新元素到链表头部
static inline void list_add_rcu(struct list_head *new, struct list_head *head)
{
__list_add_rcu(new, head, head->next);
}
//添加新元素到链表尾部
static inline void list_add_tail_rcu(struct list_head *new,
struct list_head *head)
{
__list_add_rcu(new, head->prev, head);
}
//从链表删除元素entry
static inline void list_del_rcu(struct list_head *entry)
{
__list_del_entry(entry);
entry->prev = LIST_POISON2;
}
//链表元素替换
static inline void list_replace_rcu(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->prev = old->prev;
rcu_assign_pointer(list_next_rcu(new->prev), new);
new->next->prev = new;
old->prev = LIST_POISON2;
}
对于writer,RCU操作包括:
RCU层次架构
RCU根据CPU数量的大小按照树形结构来自成其层次结构,称为RCU Hierarchy。
#ifdef CONFIG_RCU_FANOUT //每个层数最多支持的叶子数量
#define RCU_FANOUT CONFIG_RCU_FANOUT
#else /* #ifdef CONFIG_RCU_FANOUT */
# ifdef CONFIG_64BIT
# define RCU_FANOUT 64
# else
# define RCU_FANOUT 32
# endif
#endif /* #else #ifdef CONFIG_RCU_FANOUT */
#ifdef CONFIG_RCU_FANOUT_LEAF //一个子叶子的CPU数量
#define RCU_FANOUT_LEAF CONFIG_RCU_FANOUT_LEAF
#else /* #ifdef CONFIG_RCU_FANOUT_LEAF */
# ifdef CONFIG_64BIT
# define RCU_FANOUT_LEAF 64
# else
# define RCU_FANOUT_LEAF 32
# endif
#endif /* #else #ifdef CONFIG_RCU_FANOUT_LEAF */
【32核处理器的CPU层次结构】两个层次,level0 包含两个struct rcu_node, 每个struct rcu_node管理16个struct rcu_data数据结构,分别表示16个CPU独立的struct rcu_data数据结构;在level1层级,有一个struct rcu_node节点管理level0层级的两个rcu_node节点,level1层级中的rcu_node节点称为根节点,level0层级的连个rcu_node节点是叶子节点。
优化屏障
/* Optimization barrier */
/* The "volatile" is due to gcc bugs */
#define barrier() __a**__ __volatile__("": : :"memory")
//__a**__表示插入汇编语言程序;__volatile__表示组织编译对该值进行优化,确保变量使用了用户定义的精确地址,而不是装有同一信息的一些别名。memory表示修改了内存单元。
内存屏障
内存屏障,也称内存栅障或屏障指令等,是一类同步屏障指令,是编译器或CPU对内存访问操作的时候,严格按照一定顺序来执行,也就是memory barrier之前的指令和memory barrier之后的指令不会由于系统优化等原因而导致乱序。memory barrier包括两类:编译器屏障(complier barrier)和CPU屏障(cpu barrier)
The Linux kernel has eight basic CPU memory barriers:
TYPEMANDATORY**P CONDITIONAL
=================================================================
GENERAL(保证读写操作有序)mb()**p_mb()
WRITE(仅保证写操作有序)wmb()**p_wmb()
READ(仅保证读操作有序)rmb()**p_rmb()
mb()/rmab()/wmb()将硬件内存屏障插入到代码流程中,barrier插入一个优化屏障,该指令告知编译器,保存在CPU寄存器中、在屏障之前有效的所有内存地址,在屏障之后全部消失。本质,编译器在屏障之前发出的读写请求完成之前,会处理屏障之后的任何读写请求。**p_mp()/**p()_rmb()/**p_wmb()相当于硬件内存屏障,只适用于**P系统。在单处理器系统上产生的是软件屏障。内存屏障作用:解决CPU高速缓存存在的问题,无锁数据结构,内存屏障很有用处。
总结
本文主要介绍了RCU机制,包括原理、链表操作、层次架构、32核处理器的CPU层次结构,及内存屏障,包括编译器屏障、CPU屏障等。
– – 内核技术中文网 – 构建全国最权威的内核技术交流分享论坛
转载地址:一文解决RCU机制及内存优化屏障 – 圈点 – 内核技术中文网 – 构建全国最权威的内核技术交流分享论坛