Non-recursive mutex ownership - c++

I read this answer on SO:
Because the recursive mutex has a sense of ownership, the thread that grabs the mutex must be the same thread that releases the mutex. In the case of non-recursive mutexes, there is no sense of ownership and any thread can usually release the mutex no matter which thread originally took the mutex.
I'm confused by the last statement. Can one thread lock a mutex and another different thread unlock that mutex? I thought that same thread should be the only one able to unlock the mutex? Or is there any specific mutex that allows this? I hope someone can clarify.

Non-recursive mutex
Most mutexes are (or at least should be) non-recursive. A mutex is an object which can be acquired or released atomically, which allows data which is shared between multiple threads to be protected against race conditions, data corruption, and other nasty things.
A single mutex should only ever be acquired once by a single thread within the same call chain. Attempting to acquire (or hold) the same mutex twice, within the same thread context, should be considered an invalid scenario, and should be handled appropriately (usually via an ASSERT as you are breaking a fundamental contract of your code).
Recursive mutex
This should be considered a code smell, or a hack. The only way in which a recursive mutex differs from a standard mutex is that a recursive mutex can be acquired multiple times by the same thread.
The root cause of the need for a recursive mutex is lack of ownership and no clear purpose or delineation between classes. For example, your code may call into another class, which then calls back into your class. The starting class could then try to acquire the same mutex again, and because you want to avoid a crash, you implement this as a recursive mutex.
This kind of topsy-turvy class hierarchy can lead to all sorts of headaches, and a recursive mutex provides only a band-aid solution for a more fundamental architectural problem.
Regardless of the mutex type, it should always be the same thread which acquires and releases the same mutex. The general pattern that you use in code is something like this:
Thread 1
Acquire mutex A
// Modify or read shared data
Release mutex A
Thread 2
Attempt to acquire mutex A
Block as thread 1 has mutex A
When thread 1 has released mutex A, acquire it
// Modify or read shared data
Release mutex A
It gets more complicated when you have multiple mutexes that can be acquired simultaneously (say, mutex A and B). There is the risk that you'll run into a deadlock situation like this:
Thread 1
Acquire mutex A
// Access some data...
*** Context switch to thread 2 ***
Thread 2
Acquire mutex B
// Access some data
*** Context switch to thread 1 ***
Attempt to acquire mutex B
Wait for thread 2 to release mutex B
*** Context switch to thread 2 ***
Attempt to acquire mutex A
Wait for thread 1 to release mutex A
*** DEADLOCK ***
We now have a situation where each thread is waiting for the other thread to release the other lock -- this is known as the ABBA deadlock pattern.
To prevent this situation, it is important that each thread always acquires the mutexes in the same order (e.g. always A, then B).

Recursive mutexes are thread-specific by design (the same thread locking again = recursion, another thread locking meanwhile = block). Regular mutexes do not have this design and thus they can in fact be locked and unlocked in different threads.

I think this covers all your questions. Straight from linux man pages for pthreads:
If the mutex type is PTHREAD_MUTEX_NORMAL, deadlock detection shall not be provided. Attempting to relock the mutex causes deadlock. If a thread
attempts to unlock a mutex that it has not locked or a mutex which is unlocked, undefined behavior results.
If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then error checking shall be provided. If a thread attempts to relock a mutex that it has already
locked, an error shall be returned. If a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked, an error shall be
returned.
If the mutex type is PTHREAD_MUTEX_RECURSIVE, then the mutex shall maintain the concept of a lock count. When a thread successfully acquires a
mutex for the first time, the lock count shall be set to one. Every time a thread relocks this mutex, the lock count shall be incremented by one.
Each time the thread unlocks the mutex, the lock count shall be decremented by one. When the lock count reaches zero, the mutex shall become
available for other threads to acquire. If a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked, an error shall
be returned.
If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex results in undefined behavior. Attempting to unlock the mutex
if it was not locked by the calling thread results in undefined behavior. Attempting to unlock the mutex if it is not locked results in undefined
behavior.

Related

C++ Pthread Mutex Locking

I guess I'm a little unsure of how mutexs work. If a mutex gets locked after some conditional, will it only lock out threads that meet that same condition, or will it lock out all threads regardless until the mutex is unlocked?
Ex:
if (someBoolean)
pthread_mutex_lock(& mut);
someFunction();
pthread_mutex_unlock(& mut);
Will all threads be stopped from running someFunction();, or just those threads that pass through the if-statement?
You need to call pthread_mutex_lock() in order for a thread to be locked. If you call pthread_mutex lock in thread A, but not in thread B, thread B does not get locked (and you have likely defeated the purpose of mutual exclusion in your code, as it's only useful if every thread follows the same locking protocol to protect your code).
The code in question has a few issues outlined below:
if (someBoolean) //if someBoolean is shared among threads, you need to lock
//access to this variable as well.
pthread_mutex_lock(& mut);
someFunction(); //now you have some threads calling someFunction() with the lock
//held, and some calling it without the lock held, which
//defeats the purpose of mutual exclusion.
pthread_mutex_unlock(& mut); //If you did not lock the *mut* above, you must not
//attempt to unlock it.
Will all threads be stopped from running someFunction();, or just those threads that pass through the if-statement?
Only the threads for which someBoolean is true will obtain the lock. Therefore, only those threads will be prevented from calling someFunction() while someone else holds the same lock.
However, in the provided code, all threads will call pthread_mutex_unlock on the mutex, regardless of whether they actually locked it. For mutexes created with default parameters this constitutes undefined behavior and must be fixed.

why std::lock() supports deallock avoidence but std::try_lock() does not?

I thought the difference between std::lock() and std::try_lock() is only in try_lock() , if locks are not available , immediately it will return false while in the case of std::lock(), it will go in blocked state.
Cpp reference for std::lock
void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn );
Locks the given Lockable objects lock1, lock2, ..., lockn using a deadlock avoidance algorithm to avoid deadlock.
Cpp reference by try_lock
int try_lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn);
Tries to lock each of the given Lockable objects lock1, lock2, ..., lockn by calling try_lock in order beginning with the first.
I have following two questions:
Why std::lock() provides deadlock avoidence but std::try_lock doesn't?
why in std::lock , order of lock doesn't matter( it could be lock2 , lock 3, lock1, ...) while in std::try_lock() order of locks are maintained (lock1, lock2, lock3....)
Why std::lock() provides deadlock avoidence but std::try_lock doesn't?
It doesn't need to. If the try_lock fails to lock all members then it releases all members. You can't get a deadlock from try_lock if another thread owns some or all of these resources since you will return immediately.
From try_lock:
If a call to try_lock fails, no further call to try_lock is performed, unlock is called for any locked objects and a 0-based index of the object that failed to lock is returned.
why in std::lock , order of lock doesn't matter( it could be lock2 , lock 3, lock1, ...) while in std::try_lock() order of locks are maintained (lock1, lock2, lock3....)
I suspect because of ease. There is no dead-lock avoidance algorithm required because you either lock all of them, or you can't lock one in which case you release all of them. For this reason the easiest locking approach is to try_lock beginning with the first and moving through the variadic template list. Furthermore the return value indicates that it will return the index of the first failed lock. In order to achieve this you must iterate from left to right.
The answer is simple. std::try_lock does not need deadlock avoidance mechanism, as it will return immediately if a particular lock is not available and unlock all the locks which were obtained. On the other hand, std::lock() should only return once all the locks are acquired and will have them locked - and this is why it needs deadlock avoidance.
Consider the case of 2 locks A and B. Let's say, thread 2 owns the lock B, and desires to lock A. At the same time, thread 1 wants to lock A and B. With std::try_lock called at thread 1, what is going to happen is that A is successfully locked, a failed attempt to lock B is made, after which A is unlocked (and function return false) - and thread 2 successfuly locks A.
On the other hand, if a std::lock would not use deadlock avoidance, and thread 1 were to call it, the sequence of events would be: thread 1 locks A, thread 1 attempts to lock B and is stopped here, thread 2 attempts to lock A and is stopped here. And this point, neither of the threads can make progress and we have a classical deadlock.
2nd Q 1st:
Because try_lock is supposed to return the ordinal number of 1st failed lock, but lock has to do lock all locks before returning.
1st Q 2nd:
In order to avoid deadlock, the order of locking the locks must be the same among all locking threads. Thus, deadlock prevention involves reordering the inputs in a deterministic and repeatable manor. Where the ordinal of the locks is relevant to the caller, reordering the input cannot take place and deadlock prevention cannot be used.

How can implement a recursive lock using boost, that spans multiple methods?

I have a class that opens transactions, adds operations to a queue, then closes the transaction. Across the open->close lifetime I would like to employ a recursive mutex, so that only one thread can have a transaction open at any time. All other threads are blocked until the current transaction is ended.
class MyObject
{
void beginTransaction()
{
// acquire mutex
}
void endTransaction()
{
// release mutex
}
boost::recursive_mutex m_mutex;
}
I am having difficulty determining how I can use a recursive_mutex in this case, as the lock would exist longer than the scope of a single method. Can anyone suggest how I might apply locking here?
Boost (and the standard library) provide mutexes, which can be locked and unlocked, and locks, which lock mutexes in their constructor and unlocks them in their destructor. Locks are really just lightweight wrappers that are used to ensure a lock is released when leaving scope.
In your case, you would just use the mutex directly, without wrapping it in a lock.
You can call m_mutex.lock() in beginTransaction to lock the mutex, then m_mutex.unlock() in endTransaction to unlock the mutex. If another thread attempts to call m_mutex.lock() between calls, it will block until the mutex is unlocked by the owning thread in endTransaction

Use lock-free algorithm for shared memory

I want to use lock-free algorithm for shared memory for avoiding mutex. I have some processes that share data use shared memory. If a process is locking mutex and crashes, all other processes also crash.
I read some papers which implement lock-free algorithm with linked list. But in my shared memory, I can't define data structure for using on this block of memory. I have just a pointer to this block.
So I don't have any ideas for apply lock-free algorithm in my situation. I need some helps from you. Thanks and sorry if my English is very bad.
If a process is locking mutex and crashes, all other processes also crash.
Specifically for this use case there are robust mutexes:
PTHREAD_MUTEX_ROBUST
If the process containing the owning thread of a robust mutex terminates while holding the mutex lock, the next thread that acquires the mutex shall be notified about the termination by the return value [EOWNERDEAD] from the locking function. If the owning thread of a robust mutex terminates while holding the mutex lock, the next thread that acquires the mutex may be notified about the termination by the return value [EOWNERDEAD]. The notified thread can then attempt to mark the state protected by the mutex as consistent again by a call to pthread_mutex_consistent(). After a subsequent successful call to pthread_mutex_unlock(), the mutex lock shall be released and can be used normally by other threads. If the mutex is unlocked without a call to pthread_mutex_consistent(), it shall be in a permanently unusable state and all attempts to lock the mutex shall fail with the error [ENOTRECOVERABLE]. The only permissible operation on such a mutex is pthread_mutex_destroy().

Does pthread_mutex_t in linux are reentrancy (if a thread tries to acquire a lock that it already holds, the request succeeds)

I am coming from Java , so i am familiar with synchronize and not mutex.
I wonder if pthread_mutex_t is also reentrancy. if not is there another mechanism for this?
Thank you
This depends on the mutex type, the default does no checking and an attempt to lock it more than once in the same thread results in undefined behavior. Read about it here.
You can create a mutex of type PTHREAD_MUTEX_RECURSIVE to be able to recursively lock it, which is done by providing a pthread_mutexattr_t with the desired mutex type to pthread_mutex_init
According to the manual, you can declare a mutex object as PTHREAD_MUTEX_RECURSIVE:
If the mutex type is PTHREAD_MUTEX_RECURSIVE, then the mutex shall
maintain the concept of a lock count. When a thread successfully
acquires a mutex for the first time, the lock count shall be set to
one. Every time a thread relocks this mutex, the lock count shall be
incremented by one. Each time the thread unlocks the mutex, the lock
count shall be decremented by one. When the lock count reaches zero,
the mutex shall become available for other threads to acquire. If a
thread attempts to unlock a mutex that it has not locked or a mutex
which is unlocked, an error shall be returned.
See also pthread_mutex_attr_settype.
By default, pthread_mutex is not recursive, but there is a way for initialize it as recursive:
pthread_mutexattr_t Attr;
pthread_mutexattr_init(&Attr);
pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&_mutex, &Attr);
I think you don't mean reentrancy but recursiveness. Having reentrant locking with Java is impossible.
Recursive locking is simply when you already own a lock in a thread you might lock it again without any issues. Actually this is very efficient since this doesn't need any atomic operations but just a compare of the owning thread id of the mutex with the current thread id and if both are equal, an owning-counter is - non-atomically (!) - incremented.
Reentrancy is rather is asynchronous execution within the same thread. For example if you have a signal handler in C / C++ and this signal handler locks a mutex already owned by this thread in the synchronous part of the code again. I'm not aware if there are mutex implementations that can handle this situations but there's not much need for that so I guess not. I think such mutexes couldn't be as efficient as normal recursive mutexes.