rwlock
[toc] include/linux/rwlock.h 读写锁(Read-Write Lock) 允许多读者并发访问的同步原语历史与背景这项技术是为了解决什么特定问题而诞生的?读写锁(Read-Write Lock, rwlock)是为了解决一个非常普遍的并发访问模式的性能问题:对共享数据的访问是“读多写少”。 在使用简单的互斥锁(mutex)或自旋锁(spinlock)时,任何时候都只允许一个任务进入临界区,无论它是读取还是写入。这对于读操作来说是过度限制的,因为读操作本身不会修改数据,允许多个读者同时读取是安全的。如果一个数据结构被内核中成百上千个地方频繁地读取,而只被少数几个地方偶尔写入,那么使用互斥锁会导致所有读者被迫串行执行,极大地降低了系统的并发性能。 rwlock的诞生就是为了优化这种场景。它提供了一种更精细的锁定机制: 读锁(共享锁):允许多个读者同时持有读锁。 写锁(排他锁):与互斥锁一样,任何时候只允许一个写者持有写锁。 互斥规则:当有任何读者持有读锁时,写者必须等待;当有写者持有写锁时,所有读者和其他写者都必须等待。 它的发展...
mutex
[toc] kernel/locking/mutex.c 互斥锁(Mutex) 内核中基本的睡眠锁实现历史与背景这项技术是为了解决什么特定问题而诞生的?kernel/locking/mutex.c 实现的互斥锁(Mutex,Mutual Exclusion)是为了解决多任务内核中一个最基础、最普遍的并发控制问题:如何确保一段代码(临界区)在任何时刻最多只能被一个执行绪(线程或进程)执行,从而保护共享数据的完整性。 在没有互斥机制的情况下,如果多个CPU上的任务同时访问和修改同一个共享数据(如一个链表),就会导致数据损坏、状态不一致、内存泄漏等各种灾难性的后果。 mutex被设计为一种睡眠锁(Sleeping Lock),专门用于解决**进程上下文(Process Context)**中的互斥问题。它的诞生是为了与另一种锁——**自旋锁(Spinlock)**形成互补: 自旋锁适用于中断上下文或保护极短的、不容许睡眠的临界区。获取不到锁的任务会“自旋”(忙等待),浪费CPU。 如果临界区比较长,或者在临界区内需要调用可能导致睡眠的函数(如kmalloc(...
spinlock
[toc] kernel/locking/spinlock.c 自旋锁(Spinlock) 内核中最基础的高性能对称多处理器(SMP)锁历史与背景这项技术是为了解决什么特定问题而诞生的?自旋锁(Spinlock)是为了解决**对称多处理器(SMP)**系统中最基础的并发控制问题而诞生的:如何保护一段极短的、在任何执行上下文中都可能被访问的临界区。 在单处理器(UP)系统中,要保护一段临界区,最简单的方法是禁用本地中断。这样可以确保在执行临界区代码时,不会被中断处理程序打断,从而避免了并发。 然而,在多处理器(SMP)系统中,禁用本地CPU的中断并不能阻止另一个CPU同时执行并访问同一块共享数据。因此,需要一种CPU之间的互斥机制。自旋锁就是为此设计的最底层、最高效的锁。它主要解决: SMP互斥:提供一种在多个CPU之间进行互斥的机制。 原子上下文(Atomic Context)保护:中断处理程序、软中断、tasklet等上下文是不能睡眠的。自旋锁通过“忙等待”而不是“睡眠”来等待锁,因此它是唯一可以在这些原子上下文中安全使用的锁类型。 它的发展经历了...
seqlock
[toc] include/linux/seqlock.h 顺序锁(Sequence Lock) 针对读多写少场景的无锁读者优化历史与背景这项技术是为了解决什么特定问题而诞生的?seqlock(顺序锁)是一种高度特化的同步原语,它的诞生是为了解决一个在传统读写锁(rw_lock)中存在的经典性能问题:写者饥饿(Writer Starvation)。 在标准的读写锁模型中,当一个或多个读者持有读锁时,任何试图获取写锁的写者都必须等待。如果读者频繁地、接连不断地到来,那么写者可能会被无限期地延迟,即“饿死”。这在某些读操作极其频繁、写操作较少的场景下会成为严重的性能瓶颈。 seqlock通过颠覆这个模型来解决问题:它赋予写者绝对的优先权。一个写者永远不会被读者阻塞,它可以随时进入临界区并修改数据,即使当时有读者正在读取。为了在这种“不加保护”的读取中保证数据的一致性,它引入了一个序列计数器,让读者自己来检测在读取期间是否有写者介入,并在检测到冲突时进行重试。 它的发展经历了哪些重要的里程碑或版本迭代? 作为一种优化模式被引入:seqlock不是一个通用的锁,...
rwsem
[TOC] kernel/locking/rwsem.c 读写信号量(Read-Write Semaphore) 内核中可睡眠的读写锁历史与背景这项技术是为了解决什么特定问题而诞生的?kernel/locking/rwsem.c 实现的读写信号量(Read-Write Semaphore, rwsem)是为了解决rwlock_t(读写自旋锁)无法解决的一类“读多写少”场景的并发控制问题:当临界区的执行时间较长,或者在临界区内需要睡眠时,如何高效地进行读写并发控制。 rwlock_t是一个自旋锁,它要求临界区必须极短且绝对不能睡眠。然而,在内核的许多路径中(特别是与用户空间交互的系统调用),临界区可能很长,并且包含可能导致睡眠的操作(如copy_from_user、kmalloc(GFP_KERNEL)或等待I/O)。 rwsem正是为了这种可睡眠的、读多写少的场景而设计的。它是一个睡眠锁,提供了与rwlock_t相同的逻辑: 允许多个读者并发进入。 只允许一个写者独占进入。 读者和写者互斥。 当一个任务试图获取一个被占用的rwsem时,它不...
SRCU
[toc] ![[l kernel/rcu/srcu.c Sleepable Read-Copy Update (SRCU) 允许睡眠的RCU变体历史与背景这项技术是为了解决什么特定问题而诞生的?Sleepable Read-Copy Update (SRCU) 的诞生是为了解决标准RCU(包括Classic RCU和Preemptible RCU)的一个核心限制:其读侧临界区(read-side critical section)内不允许睡眠。 标准的RCU通过监控CPU的静止状态(如上下文切换、进入idle)来确定宽限期(Grace Period),而这些监控手段都假设了读者在持有“锁”(即在rcu_read_lock()和rcu_read_unlock()之间)时不会主动放弃CPU(即睡眠)。 然而,在内核中存在很多场景,开发者需要在访问一个被RCU保护的、读多写少的数据结构的同时,执行一些可能会导致睡眠的操作。例如: 与用户空间交互:调用 copy_from_user() 或 copy_to_user(),这些函数在访问的用户内存被换出到磁盘时,...
rcu
[TOC] kernel/rcu Read-Copy Update (RCU) 高性能的内核同步机制历史与背景这项技术是为了解决什么特定问题而诞生的?Read-Copy Update (RCU) 技术的诞生,是为了解决在多核处理器系统中,对**读多写少(Read-mostly)**类型共享数据进行同步时遇到的性能瓶颈问题。 传统的同步机制,如读写锁(Reader-Writer Locks),虽然允许多个读者同时访问数据,但存在以下问题: 读者开销:即使是读取操作,读者也必须获取一个锁(或至少执行原子操作来增加引用计数)。在多核环境下,这会导致缓存行在CPU之间频繁“弹跳”(cache line bouncing),造成严重的性能下降和扩展性问题。 锁争用:当写者需要获取锁时,它可能会被已有的读者阻塞,或者需要等待新的读者完成。反之,写者持有锁时,所有读者都必须等待。这种争用在高并发读取场景下尤为突出。 RCU 的核心目标就是让读者几乎零开销(wait-free)。它允许读者在访问数据时完全不需要获取任何锁、自旋锁或执行原子指令,从而消除了读者端的同步开销和扩展...
tree
[toc] kernel/rcu/tree.c Tree RCU - 应对大规模多核系统的RCU扩展性实现历史与背景这项技術是爲了解决什么特定问题而诞生的?kernel/rcu/tree.c 并不是一种新的RCU“类型”(像SRCU那样),而是标准RCU(包括Preemptible RCU)的一种高性能、高可扩展性的实现方式。它的诞生是为了解决随着多核处理器(SMP)系统中CPU核心数量急剧增加,最初的“扁平化”RCU实现所面临的严重扩展性瓶颈问题。 RCU的核心是等待一个“宽限期”(Grace Period)结束,而宽限期的结束依赖于确认系统中所有CPU都已经经历过至少一次静止状态(Quiescent State)。在早期的、核心数较少的系统中,RCU协调器可以通过检查一个全局的数据结构来轮询或追踪每个CPU的状态。 然而,当CPU核心数从个位数增长到几十、几百甚至上千时,这种“扁平化”的管理方式导致了: 全局锁/数据争用:所有CPU都需要向一个中心点报告自己的状态,或者由一个中心任务去检查所有CPU的状态。这会导致对同一个全局锁或缓存行的...
deadline
[toc] kernel/sched/deadline.c 截止时间调度器(Deadline Scheduler, SCHED_DEADLINE) 面向硬实时的可预测调度历史与背景这项技术是为了解决什么特定问题而诞生的?kernel/sched/deadline.c 实现了SCHED_DEADLINE调度策略,它的诞生是为了解决传统实时调度器(SCHED_FIFO/RR)在硬实时(Hard Real-time)和复杂系统中所面临的局限性。 SCHED_FIFO/RR基于静态优先级,虽然模型简单,但在复杂系统中存在两个主要问题: 缺乏可分析性(Analyzability):在一个包含几十个实时任务的系统中,仅仅依靠手动分配静态优先级来保证所有任务都能满足各自的截止时间,是一项极其困难且易错的工作。当任务间存在复杂的依赖关系时,几乎无法从理论上证明系统的可调度性。 任务间无隔离:SCHED_FIFO是“赢家通吃”模型。一个有bug或行为不当的高优先级任务可以无限期地运行,完全饿死所有低优先级任务,导致系统服务完全中断。它不提供任何形式的...
rt
[toc] kernel/sched/rt.c 实时调度(Real-Time Scheduling) 保证关键任务的优先执行历史与背景这项技术是为了解决什么特定问题而诞生的?kernel/sched/rt.c 是Linux内核实时调度器的核心实现。它的诞生不是为了“公平”或“高吞吐量”,而是为了解决一个截然不同的、至关重要的问题:可预测的时间行为(Predictable Temporal Behavior)。 在通用计算中(由CFS调度器处理),一个任务晚几毫秒完成通常无伤大雅。但在很多领域,任务的正确性不仅取决于计算结果,更取决于结果产生的时间。如果一个任务错过了它的截止时间(deadline),即使结果正确,也可能造成灾难性后果。这些场景包括: 工业控制:机器人手臂的控制指令必须在几毫秒内发出,否则可能导致生产事故。 电信基础设施:处理5G网络数据包的设备,必须在严格的时间窗内完成,以保证通信质量。 专业音视频处理:音频处理线程必须周期性地、准时地向声卡提供数据,否则就会出现爆音(xrun)。 金融交易:高频交易算法的执行延迟直接关系到经济效益。 ...








