PREEMPT_RT 技术实现:RCU
RCU (Read-Copy Update, 读 - 复制 - 更新)是 Linux 内核中一种专为读多写少场景优化的高性能同步机制。它的核心优势是读操作完全无锁、零开销写操作通过延迟回收保证安全极大提升多核并发效率。一、核心原理RCU 将更新操作拆分为移除替换和回收释放两个阶段并引入宽限期Grace Period确保安全。读端Reader无锁访问读者通过rcu_read_lock()和rcu_read_unlock()标记临界区无需获取锁直接访问数据。可见性读者要么看到旧版本要么看到新版本永远不会读到中间状态。写端WriterCopy复制不直接修改原数据而是创建一份副本并修改。Modify修改在副本上完成所有更新。Assign替换用原子操作rcu_assign_pointer将全局指针指向新副本。此后新读者只能看到新数据。Wait等待进入宽限期等待所有正在访问旧数据的读者完成读取。Reclaim回收宽限期结束后安全释放旧数据。关键概念宽限期 (Grace Period)定义从指针替换完成到所有 CPU 都退出读临界区的时间窗口。作用确保旧数据在没有任何读者引用时才被释放避免悬空指针Use-After-Free。静默状态Quiescent State内核将上下文切换、进入用户态、空闲循环视为 CPU 已退出读临界区的标志。二、适配PREEMPT_RT的 RCU 配置在主线 Linux 内核中RCU 的大量处理工作运行在软中断上下文此过程抢占是关闭的会造成显著延迟、损害实时性。这篇文章总结了一些相关的优化设置:RCU Configuration for Real-Time Systems, 简单总结一下就是以下的一些设定RCU 回调卸载RCU Callback OffloadingRCU 优先级提升RCU Priority BoostingRCU 加速宽限期Expedited RCU Grace Periods可抢占 RCUPreemptible RCU三、 可抢占 RCUPreemptible RCU对于RCU的一些优化操作我想着重介绍一下Preemptible RCU的实现机制。#ifdef CONFIG_PREEMPT_RCU static void rcu_preempt_read_enter(void) { WRITE_ONCE(current-rcu_read_lock_nesting, READ_ONCE(current-rcu_read_lock_nesting) 1); } /* * Preemptible RCU implementation for rcu_read_lock(). * Just increment -rcu_read_lock_nesting, shared state will be updated * if we block. */ void __rcu_read_lock(void) { rcu_preempt_read_enter(); if (IS_ENABLED(CONFIG_PROVE_LOCKING)) WARN_ON_ONCE(rcu_preempt_depth() RCU_NEST_PMAX); if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) rcu_state.gp_kthread) WRITE_ONCE(current-rcu_read_unlock_special.b.need_qs, true); barrier(); /* critical section after entry code. */ } #else /* #ifdef CONFIG_PREEMPT_RCU */ static inline void __rcu_read_lock(void) { preempt_disable(); } #endif通过上述代码对__rcu_read_lock的实现不难看出区别Preemptible RCU对比普通RCU 将preempt_disable替换成current-rcu_read_lock_nesting的嵌套层级计数。普通RCU判断宽限期结束通过判断当前是否处于禁止抢占的状态而PREEMPT_RCU则通过判断嵌套层级来确认是否可以回收旧数据。通过标记临界区方法的改变使rcu_read_lock期间无须禁用抢占。