土法炼钢兴趣小组的算法知识备份

【操作系统百科】mutex 与 rwsem

文章导航

分类入口
os
标签入口
#mutex#rwsem#adaptive-spin#sleeping-lock#lockdep

目录

spinlock 不能睡眠——持有时间长的临界区需要 mutex(互斥锁)和 rwsem(读写信号量)。

一、先看图

flowchart TD
    LOCK[mutex_lock] --> FAST{owner == 0?}
    FAST -- 是 --> GET[直接获取<br/>一条 CAS]
    FAST -- 否 --> SPIN{owner 在运行?}
    SPIN -- 是 --> ADAPTIVE[adaptive spin<br/>等 owner 释放]
    SPIN -- 否 --> SLEEP[加入等待队列<br/>schedule]
    ADAPTIVE --> RELEASED{owner 释放?}
    RELEASED -- 是 --> GET
    RELEASED -- 超时 --> SLEEP

    classDef fast fill:#3fb95022,stroke:#3fb950,color:#adbac7;
    classDef slow fill:#f0883e22,stroke:#f0883e,color:#adbac7;
    class GET,FAST fast
    class SPIN,ADAPTIVE,RELEASED slow
    class SLEEP slow

二、为什么 mutex 先自旋

如果 owner 正在另一个核上运行 → 它很可能马上释放锁 → 自旋等比睡眠+唤醒(两次上下文切换)更快。

这就是 adaptive spin(自适应自旋)。

三、mutex 实现

struct mutex {
    atomic_long_t owner;      // 持有者 task_struct * + flags
    raw_spinlock_t wait_lock; // 保护等待队列
    struct list_head wait_list;
    // ...
};

3.1 Fast path

owner == 0atomic_long_cmpxchg(&lock->owner, 0, current) → 获取。

3.2 Optimistic spinning(MCS 等待)

owner 在运行中 → 在 MCS 节点上自旋 → owner 释放时直接交接(handoff)。

3.3 Slow path

owner 不在运行 → 加入 wait_listschedule() 睡眠。

3.4 Owner handoff

防止新来者一直抢锁(插队)→ 等待队列第一个 waiter 被标记 handoff → owner 必须直接交给它。

四、rwsem(读写信号量)

struct rw_semaphore {
    atomic_long_t count;      // 读者计数 + 写者标志
    raw_spinlock_t wait_lock;
    struct list_head wait_list;
    struct task_struct *owner;
    // ...
};

4.1 语义

4.2 公平性

旧版 rwsem 不公平 → 新读者可以在写者等待时插队 → 写者饥饿。

现代 rwsem(5.x+):写者等待时,新读者排队 → 写者优先避免饥饿。

4.3 Optimistic spinning

rwsem 同样支持 adaptive spin → writer 在运行时等,不运行时睡。

五、mutex vs semaphore

特性 mutex semaphore
拥有者 有(只能 owner 释放)
recursive 不允许 N/A
adaptive spin
lockdep 支持 部分

内核建议:尽量用 mutex,不用 semaphore。semaphore 主要用于计数场景。

六、ww_mutex

Wound/Wait mutex:多锁获取时避免死锁。

ww_acquire_init(&ctx, &ww_class);
ww_mutex_lock(&lock_a, &ctx);
ret = ww_mutex_lock(&lock_b, &ctx);
if (ret == -EDEADLK) {
    ww_mutex_unlock(&lock_a);
    ww_mutex_lock_slow(&lock_b, &ctx);
    // 重试 lock_a
}

GPU 驱动(DRM/TTM)大量使用。

七、PREEMPT_RT 替换

PREEMPT_RT 内核把 mutexrt_mutex

八、lockdep 检测

lockdep 在运行时跟踪锁的获取顺序 → 检测 AB-BA 死锁模式。

============================================
WARNING: possible circular locking dependency detected

lockdep 是内核开发者的第一道防线。

九、观察

cat /proc/lock_stat                  # 锁统计(需 CONFIG_LOCK_STAT)
echo 1 > /proc/sys/kernel/lock_stat  # 启用

# lockdep
dmesg | grep -i "lock"
cat /proc/lockdep_chains

十、小结


参考文献

工具


上一篇spinlock 家族 下一篇RCU

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-05-06 · os

【操作系统百科】内核内存调试

内核内存 bug 是最难追的:UAF、OOB、double free、leak 都可能沉默数月。本文讲 KASAN 三种模式、KFENCE 生产采样、kmemleak、SLUB_DEBUG、UBSAN/KCSAN 联动。

2026-05-08 · os

【操作系统百科】VFS 四层抽象

Linux 的一切皆文件靠 VFS 实现——superblock、inode、dentry、file 四层抽象加 ops 表。本文讲 VFS 核心数据结构、dcache、inode cache、RCU lookup,以及文件系统如何插入 VFS。

2026-04-22 · os

操作系统百科

Linux 6.x 视角下的操作系统系列索引:110 篇覆盖调度、虚拟内存、文件系统与 I/O、并发、隔离、可观测性,按主题、阅读路径与关键问题三种入口组织。


By .