Reentrant mutex
In computer science, the reentrant mutex (also known as a recursive mutex or recursive lock) is a synchronization primitive that may be locked multiple times by the same thread without causing a deadlock. While a thread that attempts to lock a standard (non-reentrant) mutex that it already holds would block indefinitely, this operation succeeds on a reentrant mutex. This is achieved by associating the mutex with the thread that owns it and maintaining a lock count. The owning thread can acquire the lock multiple times, incrementing the count each time. The lock is only released for other threads to acquire once the owning thread has unlocked it the same number of times it was acquired, bringing the count to zero. MotivationA reentrant mutex solves deadlocks that can occur when a function needs to acquire a lock that is already held by the same thread. This often happens in recursive code or when one function that acquires a lock calls another function that must acquire the same lock. [1] Recursive mutexes solve the problem of non-reentrancy with regular mutexes: if a function that takes a lock and executes a callback is itself called by the callback, deadlock ensues.[2] In pseudocode, that is the following situation: Consider the following scenario in pseudocode: var m : Mutex // A standard, non-reentrant mutex, initially unlocked. function lock_and_call(i : Integer) m.lock() callback(i) m.unlock() function callback(i : Integer) if i > 0 lock_and_call(i - 1) lock_and_call(1) // Invoking the function When lock_and_call(1) is executed with a standard mutex, it results in a deadlock:
Using a reentrant mutex for m prevents this deadlock. When the second call to lock_and_call(0) attempts to lock the mutex, the operation succeeds because the thread attempting to acquire the lock is already the owner. The mutex's internal count is incremented. The lock is only fully released when both calls to lock_and_call have completed and performed their corresponding m.unlock() operations. Practical useW. Richard Stevens notes that recursive locks are "tricky" to use correctly, and recommends their use for adapting single-threaded code without changing APIs, but "only when no other solution is possible".[3] The Java language's native synchronization mechanism, monitor, uses recursive locks. Syntactically, a lock is a block of code with the 'synchronized' keyword preceding it and any Object reference in parentheses that will be used as the mutex. Inside the synchronized block, the given object can be used as a condition variable by doing a wait(), notify(), or notifyAll() on it. Thus all Objects are both recursive mutexes and condition variables.[4] Example
Software emulationSoftware emulation can be accomplished[clarification needed] using the following structure:[citation needed]
Acquisition
Release
References
|