Linux RCU(Read-Copy-Update)是一种同步机制,用于提高多处理器系统中读取频繁且写入少的数据结构的性能。在实时系统中,响应时间和预测性是非常重要的。实时性意味着系统能够在严格的时间限制内完成任务。RCU通过减少锁的需求和允许并行读取操作,提高了系统的实时性。
RCU的基本工作原理
RCU的工作原理基于一种简单的观念:对数据结构的读取操作可以并发进行,而无需加锁,只要写入操作在修改数据时保持一定的约束。它通过分离数据结构的读取和更新路径来工作。更新操作通过创建数据的一个副本来进行,修改这个副本,然后将数据结构的指针从旧数据切换到新数据。这个过程需要确保任何正在进行的读取操作在看到新数据之前完成,或者至少能够安全地完成其读取操作。
图1 Linux RCU的基本原理
如上图所示,线程4需要对某共享数据进行修改,它先用rcu_assgin_pointer解除全局指针对这个数据的引用。然后系统等待所有处理器完成一个静止状态,例如上下文的切换,这样系统中就不会再有任何线程引用这个数据结构,我们称系统完成了一个宽限期(Grace Period),这是就可以安全释放或修改相关数据结构了。可见,在整个操作完成过程中,读端临界区的开销几乎为0。反观其他基于锁的并发同步机制,读端临界区都有不可忽视的性能开销。
RCU提高实时性的关键点
首先是减少锁的竞争:在传统的锁机制中,读者和写者都需要获得锁,这在高并发环境下导致显著的性能瓶颈。RCU允许读者无锁访问数据结构,从而减少了锁的竞争,提高了实时性。
其次是并行读取方面的优化:由于读取操作不需要加锁,所以多个读取操作可以并行进行,这对于读多写少的应用场景(如大多数网络和文件系统的操作)非常有利。
再次是优化写入延迟:尽管写入操作需要更复杂的处理,RCU通过延迟释放旧数据的过程来最小化对写入路径的影响。这意味着实际更新(切换到新数据)可以迅速完成,而清理和回收旧数据可以在稍后进行,从而减少了写入操作的直接延迟。
最后是减少抖动:在高负载下,锁竞争可以导致系统性能急剧下降,这在实时系统中是不可接受的。RCU通过消除读取路径上的锁,帮助避免这种性能抖动,确保系统响应时间的可预测性。
图2 路由表同步保护机制性能对比
上图来自[1]的第9.5.4节,上图表明,在系统中的处理器个数超过50个以后,RCU对以读为主的操作,提供的保护机制,性能开销接近理想状态,其性能开销远低于顺序锁和危险指针等。
实时系统中RCU的应用
在实时系统中,RCU被用来保护诸如Netfilter的连接记录表、操作系统调度核心和内存控制等关键数据结构。通过使用RCU,实时系统可以保持高吞吐量和低延迟,即使在高并发读取的场景下也是如此。Linux RCU是一种强大的同步机制,它通过允许无锁的并行读取操作和最小化写入操作的延迟,显著提高了系统的实时性。在设计要求高性能和实时响应的系统时,RCU提供了一种有效的解决方案。然而,正确实现和使用RCU需要深入理解其工作原理和适用场景,这对系统设计者来说是一个挑战。
参考文献
[1] Paul McKenny. Is Parallel Programming Hard, And, If So, What Can You Do About It? 2nd Edition. 深入理解并行编程 第2版.