关键在于"等所有读者离开"这一步怎么判断。Linux 内核的做法很巧妙:每个 CPU 在调度时会记录一个 qs(quiescent state),内核在宽限期(grace period)里逐个检查每个 CPU 是否经过了 quiescent state。一旦所有 CPU 都经过了,就说明没有读者还在引用旧数据了,这时候回调函数才会真正释放旧内存。整个过程不需要读者做任何事情——最理想的情况下,读者就是一次普通的指针读取,零额外开销。
代价是什么?写者的延迟变高了,因为要等一个完整的宽限期才能回收内存,而这个宽限期可能长达几十毫秒。所以 RCU 只适合写者能容忍延迟的场景。另外,旧数据在宽限期结束前都占着内存,内存压力也会稍大一点。还有一点容易被忽略:RCU 读者的临界区绝不能睡眠,否则这个 CPU 永远不会进入 quiescent state,宽限期就永远结束不了,系统直接死锁。