插件窝 干货文章 带你走进Linux内核源码中最常见的数据结构之「mutex」

带你走进Linux内核源码中最常见的数据结构之「mutex」

mutex lock 信号量 data 215    来源:    2025-05-14

Linux内核中的mutex数据结构分析

mutex(互斥锁)是Linux内核中最常用的同步机制之一,用于保护临界区资源,防止多个执行路径同时访问共享数据。下面我将深入分析mutex在内核中的实现。

mutex的基本结构

在Linux内核中,mutex定义在include/linux/mutex.h中:

struct mutex {
    atomic_long_t       owner;
    spinlock_t      wait_lock;
    struct list_head    wait_list;
};

成员解析

  1. owner:原子长整型,表示当前锁的拥有者

    • 最低3位用作标志位
    • 其余位存储拥有者任务的指针
  2. wait_lock:自旋锁,用于保护wait_list的访问

  3. wait_list:等待获取该mutex的任务链表

mutex的状态标志

owner字段的低3位用作状态标志:

#define MUTEX_FLAG_WAITERS    0x01  // 有任务在等待队列中
#define MUTEX_FLAG_HANDOFF    0x02  // 需要传递所有权
#define MUTEX_FLAG_PICKUP     0x04  // 准备接收所有权

mutex的核心操作

初始化

void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
{
    atomic_long_set(&lock->owner, 0);
    spin_lock_init(&lock->wait_lock);
    INIT_LIST_HEAD(&lock->wait_list);
}

加锁(mutex_lock)

  1. 快速路径:尝试直接获取锁
  2. 慢速路径:如果快速路径失败,将当前任务加入等待队列
void __sched mutex_lock(struct mutex *lock)
{
    might_sleep();

    if (!__mutex_trylock_fast(lock))
        __mutex_lock_slowpath(lock);
}

解锁(mutex_unlock)

  1. 快速路径:直接释放锁
  2. 慢速路径:如果有等待者,需要唤醒一个等待任务
void __sched mutex_unlock(struct mutex *lock)
{
    if (__mutex_unlock_fast(lock))
        return;

    __mutex_unlock_slowpath(lock);
}

mutex的优化特性

乐观自旋(Optimistic Spinning)

当mutex被其他CPU持有但持有者正在运行时,当前CPU不会立即睡眠,而是会自旋等待一小段时间,这可以减少上下文切换的开销。

锁传递(Handoff)

当高优先级任务需要获取已被低优先级任务持有的mutex时,内核会通过MUTEX_FLAG_HANDOFF标志实现锁的传递,避免优先级反转问题。

mutex与信号量的区别

  1. 用途:mutex用于保护临界区,信号量用于管理资源计数
  2. 持有者:mutex有明确的持有者,信号量没有
  3. 递归:mutex默认不可递归,信号量可以
  4. 性能:mutex经过更多优化,在无竞争时性能更好

使用示例

#include <linux/mutex.h>

struct my_data {
    struct mutex lock;
    int shared_data;
};

void init_data(struct my_data *data)
{
    mutex_init(&data->lock);
    data->shared_data = 0;
}

void modify_data(struct my_data *data, int new_value)
{
    mutex_lock(&data->lock);
    data->shared_data = new_value;
    mutex_unlock(&data->lock);
}

性能考虑

  1. 在竞争激烈的情况下,mutex可能退化为类似信号量的行为
  2. 短临界区使用mutex性能最佳
  3. 长临界区可能需要考虑其他同步机制

mutex是Linux内核中精心优化的同步原语,理解其内部实现有助于编写更高效和安全的内核代码。