一、为什么需要 RCU

在多核时代,传统的读写锁(rwlock)和互斥锁(mutex)都显露出明显的可扩展性瓶颈。RCU(Read-Copy-Update)是Linux内核的一种同步原语,它通过“复制-更新”的思路实现了读者的真正无锁化——读者不需要获取任何锁、不会被写者阻塞、甚至不会影响其他读者性能。

本文将深入拆解 RCU 的设计哲学、核心数据结构、 API 的使用模式与内部实现,并结合生产环境中的几种典型场景(链表遍历、哈希表查找、跨 CPU 配置读取)给出实战经验与性能教训。

二、核心概念

rcu_read_lock / rcu_read_unlock: 生命读取侧临界区的入口与出口。读者在读取自由指针前必须入 rcu_dereference 保护门。

synchronize_rcu: 同步等待 “宽限期” 完成。由写者调用,阻塞直到所有于 GP 开始前已经进入静止态的 CPU 完成一次静止态转移,从而保证读者不会再读到被删除节点的旧数据。

call_rcu: 异步版的 synchronize_rcu,在宣告 GP 完成后通过回调释放旧数据,避免对写者影响。

kfree_rcu: 为 kfree 特别优化的 call_rcu 包装。

三、内核核心数据结构


struct rcu_head { struct rcu_head *next; void (*func)(struct rcu_head *); };
struct rcu_node { unsigned long gpnum; unsigned long completed; struct rcu_node *parent; };
struct rcu_state { struct rcu_node node[NR_CPUS]; };

四、链表删除实战


spin_lock(&lock);
list_del_rcu(&p->list);
spin_unlock(&lock);
call_rcu(&p->rcu, rcu_free);

五、性能对比

在读多写少场景下,RCU 读取延迟恒定不变;rwlock 随核数增加而恶化;seqlock 读取失败需重试。

六、最佳实践

1. 慢查找场景优先用 RCU

2. 写入同步时记得用 call_rcu 释放节点

3. 不要滥用 synchronize_rcu

七、VFS 中的 RCU 示例


rcu_read_lock();
pid = idr_find(&ns->pid_idr, nr);
rcu_read_unlock();

八、总结

RCU 通过将“读取”与“更新”解联,实现了读取侧的无锁化。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部