【问题标题】:How a thread which is blocked while trying to mutex_lock get to know that the lock is released by another thread?尝试互斥锁时被阻塞的线程如何知道锁已被另一个线程释放?
【发布时间】:2020-12-30 04:31:41
【问题描述】:

在 Linux 中,我有一个场景,两个线程执行一个临界区,一个获取锁(线程 A),另一个(线程 B)将等待锁。后来threadA释放了互斥锁。我试图了解 threadB 将如何移动到运行状态并获取锁? threadB(或操作系统)如何知道线程A释放了锁?

我有一个理论,如果我错了,请纠正。线程 B 进入 TASK_INTERRUPTABLE(在互斥锁处阻塞,因此等待)状态,当线程 A 解锁互斥锁并返回运行队列(TASK_RUNNING)时,它会收到信号。

【问题讨论】:

    标签: multithreading linux-kernel synchronization mutex


    【解决方案1】:

    Linux 互斥体结构跟踪互斥体的当前所有者(如果有):

    struct mutex {
        atomic_long_t       owner;
        // ...
    

    还有一个结构可以跟踪其他任务正在等待互斥锁:

    /*
     * This is the control structure for tasks blocked on mutex,
     * which resides on the blocked task's kernel stack:
     */
    struct mutex_waiter {
        struct list_head    list;
        struct task_struct  *task;
        struct ww_acquire_ctx   *ww_ctx;
    #ifdef CONFIG_DEBUG_MUTEXES
        void            *magic;
    #endif
    };
    

    相当简单,当你解锁一个互斥体时,内核会查看其他任务在那个互斥体上等待。它选择其中一个成为所有者,设置互斥锁的所有者字段以引用所选任务,然后从等待互斥锁的任务列表中删除该任务。到那时,任务至少很有可能已被解除阻塞,在这种情况下,一旦解除阻塞,它就可以运行了。此时,由调度程序决定何时运行它。

    优化

    由于互斥体被大量使用,并且它们被锁定和解锁的次数很多,因此它们使用了一些优化来帮助提高速度。例如,考虑以下情况:

    /*
     * @owner: contains: 'struct task_struct *' to the current lock owner,
     * NULL means not owned. Since task_struct pointers are aligned at
     * at least L1_CACHE_BYTES, we have low bits to store extra state.
     *
     * Bit0 indicates a non-empty waiter list; unlock must issue a wakeup.
     * Bit1 indicates unlock needs to hand the lock to the top-waiter
     * Bit2 indicates handoff has been done and we're waiting for pickup.
     */
    #define MUTEX_FLAG_WAITERS  0x01
    #define MUTEX_FLAG_HANDOFF  0x02
    #define MUTEX_FLAG_PICKUP   0x04
    
    #define MUTEX_FLAGS     0x07
    

    因此,当您要求内核解锁互斥锁时,它可以“浏览”所有者指针中的某一位以确定这是否是“简单”情况(没有人在等待互斥锁,所以只需将其标记为解锁,然后出发),或者更复杂的任务(至少有一个任务在互斥体上等待,因此需要选择一个任务来解除阻塞,并将其标记为互斥体的新所有者。

    参考文献

    https://github.com/torvalds/linux/blob/master/include/linux/mutex.h https://github.com/torvalds/linux/blob/master/kernel/locking/mutex.c

    免责声明

    在我写这个答案时,上面的代码摘录(我相信)是最新的。但如上所述,互斥锁被大量使用。如果您在 5 或 10 年后查看互斥锁的代码,您可能会发现有人在优化代码方面做了一些工作,因此它可能与我上面引用的内容不完全匹配。大多数概念可能保持相似,但细节(尤其是优化)的变化是意料之中的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 2021-11-08
      • 2014-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多