• 内核中的互斥锁的使用


    在内核中结构体struct mutex的定义

    // include/linux/mutex.h
    
    /*
     * Simple, straightforward mutexes with strict semantics:
     *
     * - only one task can hold the mutex at a time
     * - only the owner can unlock the mutex
     * - multiple unlocks are not permitted
     * - recursive locking is not permitted
     * - a mutex object must be initialized via the API
     * - a mutex object must not be initialized via memset or copying
     * - task may not exit with mutex held
     * - memory areas where held locks reside must not be freed
     * - held mutexes must not be reinitialized
     * - mutexes may not be used in hardware or software interrupt
     *   contexts such as tasklets and timers
     *
     * These semantics are fully enforced when DEBUG_MUTEXES is
     * enabled. Furthermore, besides enforcing the above rules, the mutex
     * debugging code also implements a number of additional features
     * that make lock debugging easier and faster:
     *
     * - uses symbolic names of mutexes, whenever they are printed in debug output
     * - point-of-acquire tracking, symbolic lookup of function names
     * - list of all locks held in the system, printout of them
     * - owner tracking
     * - detects self-recursing locks and prints out all relevant info
     * - detects multi-task circular deadlocks and prints out all affected
     *   locks and tasks (and only those tasks)
     */
    struct mutex {
    	atomic_long_t		owner;
    	spinlock_t		wait_lock;
    #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
    	struct optimistic_spin_queue osq; /* Spinner MCS lock */
    #endif
    	struct list_head	wait_list;
    #ifdef CONFIG_DEBUG_MUTEXES
    	void			*magic;
    #endif
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    	struct lockdep_map	dep_map;
    #endif
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    竞争者从调度器的运行队列中删除,放入处于睡眠状态的等待链表(wait_list)中,然后内核调度并执行其他任务。当锁被释放时,等待队列中的等待者被唤醒,从wait_list中溢出,然后被重新调度。

    相关函数

    // 静态声明
    DEFINE_MUTEX(struct mutex);
    
    // 动态声明
    struct mutex test_mutex;
    mutex_init(&test_mutex);
    
    // 获取互斥锁
    void mutex_lock(struct mutex *lock);
    int mutex_lock_interruptible(struct mutex *lock);
    int mutex_lock_killable(struct mutex *lock);
    
    // 解锁
    void mutex_unlock(struct mutex *lock);
    
    // 检查互斥锁是否已经被持有
    int mutex_is_locked(struct mutex *lock);
    
    // 尝试获取互斥锁,如果没有被锁定,则获取互斥锁
    int mutex_trylock(struct mutex *lock);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    与等待队列的可终端函数一样,建议使用mutex_lock_interruptible(),它使驱动可以被所有信号中断,mutex_lock_killable(),只有杀死进程的信号才能中断驱动程序,也就是说mutex_lock()不响应所有的信号,建议的使用组合为mutex_lock()+mutex_unlock_interruptible()

    从内核函数说明来看,需要严格遵守一些规则。

    • 一次只能有一个任务持有互斥锁
    • 只能有互斥锁的持有者才能解锁
    • 不允许多次解锁
    • 不允许递归锁定
    • 互斥对象必须通过 API 初始化
    • 互斥对象不得通过memset或复制进行初始化
    • 任务可能不会在持有互斥锁的情况下退出,由于互斥锁保持锁定,竞争者可能永远等待(睡眠)
    • 不得释放持有锁所在的内存区域
    • 不得重新初始化持有的互斥锁
    • 互斥锁不能用于硬件或软件中断
    • 由于互斥锁涉及重新调度,互斥锁不能用在原子上下文中,如Tasklet和定时器
  • 相关阅读:
    Java中控制多线程顺序执行
    C++多线程学习05 超时锁,递归锁与共享锁
    互联网资讯查询易语言代码
    【设计模式】Java设计模式 - 迭代器模式
    (已导出)【kubernetes系列学习】client-go学习与实践
    JavaScript 函数 function
    如何管理和维护组件库?
    基于springboot、vue汽车租赁系统
    免费SaaS敏捷管理工具
    C语言实现AES加密算法的示例代码
  • 原文地址:https://blog.csdn.net/qq_42931917/article/details/127829495