找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1757

积分

0

好友

263

主题
发表于 3 天前 | 查看: 6| 回复: 0

《Linux 内核 MCS Spin Lock 原理》 一文中,我们探讨了 MCS Spin Lock 的实现。这种锁机制在实现先来先服务的公平性同时,也有效解决了传统自旋锁在多核高争用下因“缓存行颠簸”导致的性能瓶颈。然而,Linux 内核并未直接采用原始的 MCS 锁,而是基于其思想发展出了一种更优的变体——Queued Spin Lock(排队自旋锁)。本文将深入剖析其工作原理。

Linux 内核选择不直接使用 MCS 锁,一个核心原因在于结构兼容性问题。传统的 spinlock_t 结构体本质上仅占用 4 个字节,而 struct mcs_spinlock 则需要 16 字节,二者在内存布局上无法兼容。考虑到内核中大量自旋锁相关 API 都以 spinlock_t 为参数,强行更改为 mcs_spinlock 将引发连锁改动,这无疑是不可行的。

MCS锁与传统锁结构对比

因此,内核开发者巧妙地设计出了 Queued Spin Lock。其核心数据结构 struct qspinlock 同样只有 4 个字节,能够无缝替换传统的 spinlock_t。更重要的是,它在底层继承了 MCS 锁的精髓,在保障公平性的同时,依然能够有效避免多处理器争抢锁时的缓存行颠簸问题。

Queued Spin Lock 引入了一种分级等待策略,与 MCS Lock 将所有等待 CPU 都放入队列不同,它将竞争者划分为 4 种角色,并在不同位置上自旋:

  • Owner:锁的当前持有者。
  • Pender:第一顺位等待者。当 Owner 释放锁时,它将直接获得锁。
  • Successor:MCS 等待队列的队头节点,即第二顺位等待者。第二顺位及之后的等待者才会进入 MCS 队列。
  • Queuer:MCS 等待队列中,位于 Successor 之后的其他等待者。

struct qspinlock 的设计堪称精妙,它将 MCS 锁的思想压缩进了一个 32 位整数中:

Queued Spin Lock 结构布局

该结构体使用一个联合体(union)将一个 32 位的 val 变量划分为不同的位域(以小端序为例):

  • locked (Bit 0-7):表示锁是否被持有(0=空闲,1=已持有)。Pender 角色会在此位上自旋等待。
  • pending (Bit 8-15):表示是否存在第一顺位等待者(Pender),0 为否,1 为是。
  • locked_pending (Bit 0-15)lockedpending 字段的组合,用于判断锁当前是否有持有者(Owner)或第一顺位等待者(Pender)。Successor 角色会在此组合位上自旋等待。
  • tail (Bit 16-31):指向 MCS 等待队列的尾部节点。这 16 位并非直接指针,而是一个索引,用于定位具体的 MCS 节点。

Queued Spin Lock 使用一个每处理器(Per-CPU)的 struct qnode 数组来管理 MCS 队列。每个 qnode 主要包含一个 struct mcs_spinlock 节点。每个 CPU 上预分配了 4 个(MAX_NODES=4qnode,分别对应进程、软中断、硬中断以及 NMI 这四种可能获取自旋锁的上下文,因为一个 CPU 上最多只会有这四种上下文试图竞争锁(针对不同锁)。当 CPU 需要进入 MCS 队列排队时,它会根据当前运行的上下文,选取对应的 MCS 节点并插入队列。

Per-CPU qnode 数组

那么,CPU 何时需要进入 MCS 队列等待呢?当锁的等待者超过 1 个(即除了 Pender 外,还有 Successor 或 Queuer)时,后续的等待者就必须在 MCS 队列中排队。此时,tail 字段的值非零,它由两部分构成:

  • tail index (Bit 16-17, 2 bits):队尾 MCS 节点在其所属 CPU 的 qnodes 数组中的索引(0-3)。
  • tail cpu (Bit 18-31, 14 bits):队尾 MCS 节点所属 CPU 的编号加 1(加 1 是为了区分 CPU 0 和空队列状态)。

通过 tail cputail index,内核即可精确定位到 MCS 等待队列尾部 CPU 所对应的 struct mcs_spinlock 节点。这种设计对于理解 Linux 内核并发编程至关重要,相关的高级同步机制都可以在我们的 网络/系统 板块找到深度解析。




上一篇:PyTorch ATen计算引擎源码级解析:Tensor、内存管理与跨后端调度
下一篇:从入门到进阶:Claude Code安装配置与国内模型实践指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 19:01 , Processed in 0.198578 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表