互斥体的实现和信号
当一个互斥锁已经被T1锁定,并且T2试图锁定它时,T2的过程是什么?
我认为它是这样的:
-T2尝试锁定,失败,可能是自旋锁定,然后调用yield ...
-T2计划执行几次,尝试锁定失败,产生...
- 最终T1解锁,T2计划执行并设法锁定互斥锁...
T1解锁是否明确向调度程序或其他线程发出互斥锁已解锁的信号? 或者它只是解锁,并让调度程序安排阻塞的线程,当它觉得适合这样做(又称调度程序没有封锁线程的概念,并不把它们视为特殊)?
总之:是的,也许......
这是实现细节,如果没有至少知道你正在讨论哪个操作系统,这很难说。 通常,解锁互斥锁只会将等待的线程标记为“可运行”,但不会(必然)在当时调用调度程序 - 即使调用调度程序,也不表示T2将成为下一个线程跑步。
在Linux中,代码输入mutex_unlock()
,它检查是否有任何等待任务(通过检查锁计数是否小于零 - 它从1开始解锁,一个锁请求将其归零,进一步试图锁定会使其消极)。 如果还有一个等待进程,它会调用一个“缓慢路径解锁”,它通过一些重定向函数来允许实现细节,最终以__mutex_unlock_common_slowpath
- 进一步下行几行, wake_up_process
,最终结束在try_to_wake_up
- 这本质上只是将任务排队为“准备运行”,然后调用调度程序(通过几层功能!)
这取决于您的操作系统。 我已经看到了只是旋转,旋转的yield
,内核中的通用条件变量,用户级控制的调度以及具有内核支持的专用锁定原语。
纺纱和纺纱的yield
可怕。 理论上用户级控制的调度(请参阅调度程序激活)应该具有最佳性能,但据我所知,没有人在任何情况下都能正常工作。 内核中的通用条件变量和具有内核支持的专用锁定原语应该与Linux中的futex差不多,就像后者的最好例子。
有些情况下纺纱可以有更好的表现。 在Solaris中,内核中的某些锁定基元具有自适应模式,只要持有锁的进程在不同的CPU上运行,锁就会自动旋转。 如果锁主人睡觉或被抢先,锁侍者也会入睡。 在其他内核中有一些类锁,其中锁拥有者不能在抢锁时被抢占或睡眠,所以在这些情况下,旋转也很有效。 一般来说,特别是在用户区,纺纱有这样可怕的堕落情况(纺纱过程一直在旋转,直到它被抢占,让锁主人跑),这对性能来说是非常糟糕的。 请注意,像futex
这样的专门锁定原语可以实现像这样的优化,这是通用条件变量通常无法实现的。
假设我们有以下情况:
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.
*系统调用解锁应该通知所有阻塞的互斥锁的锁定 任务/进程/线程 。 他们然后计划执行。 这并不意味着他们被执行,因为可能已经有人在执行。 正如其他人所说,这取决于实施过程是如何完成的。 如果你真的想学好这本书,我会推荐这本书
链接地址: http://www.djcxy.com/p/84841.html