问题 互斥实现和信令


当互斥锁已经被T1锁定,并且T2试图锁定它时,T2的过程是什么?

我认为它是这样的:

-T2试图锁定,失败,也许是自旋锁,然后调用yield ...
  -T2计划执行几次,尝试锁定失败,产生...
   - 最终T1解锁,T2计划执行并设法锁定互斥锁...

T1解锁是否明确地向调度程序或其他线程发出信号,表示互斥锁已解锁?或者它只是解锁,并让调度程序在感觉适合时调度被阻塞的线程(也称调度程序没有阻塞线程的概念并且不将它们视为特殊)?


6144
2018-02-26 13:20


起源

I think 互斥原则保证没有2个或更多线程同时进入临界区。现在,无论您是否有一个试图锁定互斥锁的线程队列,或者您只是忙着等待互斥锁是免费的,取决于您如何实现它以及您对互斥锁的需求。例如, mutex 在RTOS中,如VxWorks实现优先级上限协议,在通用OS(GPOS)中可能不需要。 - Raj


答案:


简而言之:是的,也许......

这是实现细节,如果不知道您正在谈论哪个操作系统,就很难说。通常,解锁互斥锁只会将等待线程标记为“可运行”,但不会(必然)在此时调用调度程序 - 即使调用调度程序,也不意味着T2将成为下一个线程跑步。

在Linux中,代码进入 mutex_unlock() 检查是否有任何等待任务(通过检查锁定计数是否小于零 - 它从1开始解锁,单个锁定请求将其置为零,进一步锁定尝试将使其为负)。如果有进一步的等待过程,它会调用“慢速路径解锁”,通过一些重定向功能来实现详细信息,最终进入 __mutex_unlock_common_slowpath  - 向下几行,有一个电话 wake_up_process 最终结束了 try_to_wake_up  - 基本上只是将任务排队为“准备运行”,然后调用调度程序(通过几层函数!)


3
2018-02-26 13:52



所以你说在linux线程上块被标记为不可运行(所以sched不会在它被标记为可运行之前安排它) - NoSenseEtAl
对,那是正确的。这假设您正在使用内核互斥锁',这可能不是什么,例如,pthread_mutex实现。 - Mats Petersson
非常好的答案...顺便说一句,没有我打扰你...你能否迅速说出futex是否与此有何不同之处。 - NoSenseEtAl
我快速浏览了一下 futex 代码,它看起来完全不同,并且在内核中是一个更大的功能... - Mats Petersson


这取决于您的操作系统。我看到只是旋转,旋转着 yield,内核中的通用条件变量,用户域控制的调度和具有内核支持的专用锁定原语。

纺纱和纺纱 yield 表现糟糕。理论上用户控制​​的调度(见 调度程序激活)应该具有最佳性能,但据我所知,在任何情况下都没有人能够正常工作。内核中的通用条件变量和具有内核支持的专用锁定原语应该或多或少地执行相同的操作 futex的 在Linux中作为后者的最佳例子。

在某些情况下,纺纱可以有更好的性能。在Solaris中,内核中的某些锁定原语具有自适应模式,只要持有锁的进程在不同的cpu上运行,锁就会自动旋转。如果锁具所有者睡觉或被抢占,锁定服务员也会进入睡眠状态。在其他内核中,存在锁定类别,锁定所有者在锁定时不能被抢占或休眠,因此在这些情况下,旋转也很有效。一般来说,特别是在用户空间中,旋转具有如此可怕的退化情况(旋转过程旋转直到它被抢占以让锁拥有者运行)这对性能非常不利。请注意专门的锁定原语 futex可以实现这样的优化,通用条件变量通常不能实现。


6
2018-02-26 13:44



不错的A,但是“旋转和旋转,产量有可怕的性能”应该是合格的......我可以想象在低锁争用和锁定量低的情况下螺旋锁快速的情况。 - NoSenseEtAl
当没有争用时,所有锁都非常有效。当争用率很高时,精心设计的锁定方法也很有效。它还取决于可用处理器的数量 - 单个处理器系统上的“旋转”等待是可怕的,因为当前持有锁的另一个线程将无法运行,并且T2正在使用所有CPU来检查T1是否谁没有开始运行已经释放了锁 - 这对CPU时间的使用非常无用。 - Mats Petersson
@Mats我在考虑多核系统,但是我同意你的单核心。 - NoSenseEtAl


假设我们有以下场景:

 1. T1 got M1. M1 locked.
 2. T2 tries to get M1 and gets blocked as M1 is locked.
 3. T3 tries to get M1 and gets blocked as M1 is locked.
 4. ...some time later...
 5. T1 unlocks M1.*
 6. T2 got M1.
 7. T3 is unblocked and tries to get M1 but is blocked again as T2 got M1 first.

*系统调用, 开锁, 应该 通知全部 受阻 任务/进程/线程 这些在互斥锁上被阻止了 锁定电话。他们就是这样 计划 执行。这并不意味着他们被执行,因为可能已经有人执行。正如其他人所说,它取决于实现如何完成。如果你真的想学好这个我会推荐这个


1
2018-02-26 14:02