什么是重入锁和概念?
我总是感到困惑。 有人会解释不同情况下的折返意味着什么? 你为什么要使用可重入和不可重入?
说pthread(posix)locking原语,他们是否重入? 使用它们应该避免哪些缺陷?
互斥体是否可重入?
重入locking
可重入锁是进程可以多次声明锁而不会自行阻塞的锁。 在跟踪是否已经抓住锁的情况下,这很有用。 如果一个锁是不可重入的,那么你可以抓住这个锁,然后当你再次抓住它时阻塞,从而使自己的进程死锁。
一般来说,重入是代码的一个属性,它没有中央可变状态,如果代码在执行时被调用,则可能会被破坏。 这样的调用可以由另一个线程来完成,也可以由源自代码本身的执行pathrecursion地进行。
如果代码依赖于在执行过程中可以更新的共享状态,那么这个状态是不可重入的,至less如果这个更新可能会破坏它的话。
用于重入locking的用例
可重入locking应用程序的一个(有点generics和人为的)例子可能是:
-
你有一些计算涉及遍历一个图的algorithm(也许在其中有周期)。 由于循环或由于到同一节点的多条path,遍历可能会多次访问同一个节点。
-
数据结构受到并发访问的限制,可能由于某种原因更新,也可能由另一个线程更新。 您需要能够locking各个节点,以处理由于竞态条件而导致的潜在数据损坏。 出于某种原因(也许性能),你不希望全局locking整个数据结构。
-
你的计算不能保留你访问过什么节点的完整信息,或者你正在使用一个不允许“我以前在这里”的数据结构来快速回答。
这种情况的一个例子是Dijkstraalgorithm的简单实现,其优先级队列被实现为二进制堆或者使用简单链表作为队列的宽度优先search。 在这些情况下,扫描队列中现有的插入是O(N),你可能不想在每次迭代时都这样做。
在这种情况下,跟踪你已经获得的锁是昂贵的。 假设您想要在节点级别执行locking,则可重入locking机制可以减轻您是否曾经访问节点的需要。 您可以盲目地locking节点,也许在将其从队列中popup之后将其解锁。
重入互斥体
一个简单的互斥体是不可重入的,因为在给定的时间只有一个线程可以处于关键部分。 如果你抓住互斥锁,然后尝试再次抓住它,一个简单的互斥体没有足够的信息来告诉谁以前持有它。 要做到这一点recursion,你需要一个机制,每个线程有一个标记,所以你可以告诉谁抓住了互斥体。 这使得互斥体机制更加昂贵,所以你可能不希望在所有情况下都这样做。
IIRC POSIX线程API提供了可重入和不可重入互斥体的选项。
通过重入锁,可以编写一个方法M
,对资源A
进行locking,然后recursion地调用M
或者从已经对A
进行locking的代码中调用M
使用非重入locking,您需要M
两个版本,一个是locking的,一个是不locking的,另外还有一个逻辑可以调用正确的locking。
可重入锁在本教程中有很好的描述。
本教程中的示例与关于遍历图的答案相比较less得多。 重入锁在非常简单的情况下非常有用。