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

【操作系统百科】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-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。

2026-05-03 · os

【操作系统百科】Slab/SLUB 分配器

buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。


By .