何时使用recursion互斥?

我知道recursion互斥锁允许互斥锁被locking不止一次而没有发生死锁,应该解锁相同的次数。 但是在什么情况下你需要使用recursion互斥? 我正在寻找devise/代码级别的情况。

例如,当您有recursion调用它的函数时,并且您想要对其进行同步访问:

void foo() { ... mutex_acquire(); ... foo(); ... mutex_release(); } 

如果没有recursion互斥量,那么必须首先创build一个“入口点”函数,而当您有一组相互recursion的函数时,这会变得非常麻烦。 没有recursion互斥体:

 void foo_entry() { mutex_acquire(); foo(); mutex_release(); } void foo() { ... foo(); ... } 

recursion和非recursion互斥体有不同的用例 。 没有互斥体types可以很容易地取代其他。 非recursion互斥量具有较less的开销,recursion互斥量在某些情况下有用或甚至需要语义,并且在其他情况下危险甚至破坏语义。 在大多数情况下,根据非recursion互斥体的使用情况,有人可以使用recursion互斥体replace任何策略,使用不同的更安全更有效的策略。

  • 如果你只是想排除其他线程使用你的互斥体保护资源,那么你可以使用任何互斥体types,但可能希望使用非recursion互斥体,因为它的开销较小。
  • 如果你想recursion地调用函数,locking相同的互斥量,那么它们也是
    • 必须使用一个recursion互斥体 ,或者
    • 必须一次又一次解锁和locking同一个非recursion互斥体(注意并发线程!)(假设这在语义上是合理的,它仍然可能是一个性能问题),或者
    • 必须以某种方式注释他们已经locking的互斥体(模拟recursion所有权/互斥体)。
  • 如果要从一组这样的对象中locking几个受互斥锁保护的对象,其中这些对象可以通过合并构build,您可以select
    • 每个对象使用一个互斥体 ,允许更多的线程并行工作,或
    • 为每个对象使用对任何可能的共享recursion互斥体的 引用 ,降低无法将所有互斥锁locking在一起的可能性,或者
    • 为每个对象使用一个可比较的参考引用任何可能共享的非recursion互斥 ,绕过多次locking的意图。
  • 如果你想在一个不同于已被locking的线程中释放一个锁,那么你必须使用非recursion锁(或recursion锁,它明确允许这个而不是抛出exception)。
  • 如果要使用同步variables ,则需要在等待任何同步variables的同时显式解锁互斥锁 ,以便允许资源在其他线程中使用。 这对于非recursion互斥体来说是完全可能的,因为recursion互斥体可能已经被当前函数的调用者locking了。

如果您想查看使用recursion互斥的代码示例,请查看Linux / Unix的“Electric Fence”的源代码。 在Valgrind出现之前,Twas是寻找“边界检查”读/写超限和欠载以及使用释放内存的常见Unix工具之一。

只需编译并链接电子围栏(使用gcc / g ++选项-g),然后使用链接选项-lefence将其与软件链接,然后开始逐步调用malloc / free。 http://elinux.org/Electric_Fence

我今天遇到了recursion互斥体的需求,我想这可能是到目前为止发布的答案中最简单的一个例子:这是一个公开两个API函数Process(…)和Reset()的类。

 public void Process(...) { acquire_mutex(mMutex); // Heavy processing ... reset(); ... release_mutex(mMutex); } public void reset() { acquire_mutex(mMutex); // Reset ... release_mutex(mMutex); } 

这两个函数都不能同时运行,因为它们修改了类的内部,所以我想使用互斥锁。 问题是,Process()在内部调用reset(),并且由于已经获取了mMutex,所以会产生死锁。 用recursion锁来locking它们可以解决这个问题。

如果一个线程阻塞试图获得已经拥有的互斥量(再次),那肯定会是一个问题。

是否有理由不允许一个互斥体被同一个线程多次获取?