为了账号安全,请及时绑定邮箱和手机立即绑定

递归锁定(互斥锁)与非递归锁定(互斥锁)

/ 猿问

递归锁定(互斥锁)与非递归锁定(互斥锁)

递归锁定(互斥锁)与非递归锁定(互斥锁

POSIX允许互斥锁递归。这意味着同一个线程可以锁定相同的互斥锁两次并且不会死锁。当然它还需要解锁两次,否则没有其他线程可以获得互斥锁。并非所有支持pthread的系统都支持递归互斥锁,但如果它们想要符合POSIX,则必须使用

其他API(更高级别的API)通常也提供互斥锁,通常称为锁定。一些系统/语言(例如Cocoa Objective-C)提供递归和非递归互斥体。有些语言也只提供一种或另一种语言。例如,在Java中,互斥锁总是递归的(同一个线程可能在同一个对象上“同步”两次)。根据它们提供的其他线程功能,没有递归互斥体可能没有问题,因为它们可以很容易地自己编写(我已经在更简单的互斥/条件操作的基础上自己实现了递归互斥锁)。

我真的不明白:什么是非递归互斥量有用?如果它锁定相同的互斥锁两次,为什么我想要一个线程死锁?即使是可以避免这种情况的高级语言(例如测试它是否会死锁并抛出异常)通常也不会这样做。他们会让线程陷入僵局。

这只适用于我意外锁定它两次并且只解锁一次的情况,并且在递归互斥锁的情况下,它会更难找到问题,所以相反我立即死锁以查看错误锁定出现在哪里?但是我不能在解锁时返回一个锁定计数器,在某种情况下,我确定我已经释放了最后一个锁并且计数器不为零,我可以抛出异常或记录问题吗?或者是否有其他更有用的非递归互斥体用例我看不到?或者它可能只是性能,因为非递归互斥体可能比递归互斥体略快?但是,我对此进行了测试,差异确实不大。


查看完整描述

3 回答

?
慕前端131612

递归和非递归互斥体之间的区别与所有权有关。在递归互斥锁的情况下,内核必须跟踪第一次实际获得互斥锁的线程,以便它可以检测递归与应该阻塞的不同线程之间的差异。正如另一个答案所指出的那样,在存储该上下文的存储器方面以及维护它所需的周期方面存在额外开销的问题。

但是,这里还有其他考虑因素。

因为递归互斥锁具有所有权感,所以抓取互斥锁的线程必须与释放互斥锁的线程相同。在非递归互斥锁的情况下,没有所有权感,任何线程通常都可以释放互斥锁,无论哪个线程最初使用互斥锁。在许多情况下,这种类型的“互斥体”实际上更像是一种信号量动作,您不必将互斥体用作排除设备,而是将其用作两个或多个线程之间的同步或信号设备。

另一个在互斥体中具有所有权感的属性是支持优先级继承的能力。因为内核可以跟踪拥有互斥锁的线程以及所有阻塞程序的标识,所以在优先级线程系统中,可以将当前拥有互斥锁的线程的优先级升级到最高优先级线程的优先级目前阻止互斥锁。这种继承防止了在这种情况下可能发生的优先级倒置问题。(请注意,并非所有系统都支持此类互斥锁上的优先级继承,但它是通过所有权概念实现的另一个功能)。

如果您参考经典的VxWorks RTOS内核,它们定义了三种机制:

  • mutex - 支持递归和可选的优先级继承。该机制通常用于以连贯的方式保护数据的关键部分。

  • 二进制信号量 - 没有递归,没有继承,简单排除,接受者和给予者不必是相同的线程,广播版本可用。该机制可用于保护关键部分,但对于线程之间的相干信令或同步也特别有用。

  • 计数信号量 - 没有递归或继承,充当来自任何所需初始计数的连贯资源计数器,线程仅阻止对资源的净计数为零。

同样,这在平台上有所不同 - 特别是他们称之为这些东西,但这应该代表了概念和各种机制。


查看完整回答
反对 回复 2019-08-14
  • 3 回答
  • 0 关注
  • 473 浏览
我要回答

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信