When a thread waits on a condition variable, the associated mutex is (atomically) released (unlocked). When that condition variable is signaled (by a different thread), one (for signal) or all (for broadcast) waiting thread(s) is/are awakened, automatically re-acquiring (locking) the mutex.
What will happen if one or more other threads are waiting to acquire (lock) that same mutex, but not waiting on the same condition? Are the thread(s) waiting on the condition variable guaranteed to be awakened (and thus acquire the mutex) before the mutex can be acquired (locked) by the other threads, or could the other thread(s) acquire (lock) the mutex before the thread(s) waiting on the condition variable?
[Note: the example below is simplified for clarity. Thread_B does not really start Thread_C, but Thread_C is guaranteed to not be running until after Thread_B has acquired the mutex - it does not compete with Thread_B for the mutex after Thread_A waits on the condition variable]
Thread_A:
pthread_mutex_lock(&myMutex);
while (!someState) {
pthread_cond_wait(&myCondVar,&myMutex);
}
// do something
pthread_mutex_unlock(&myMutex);
Thread_B:
pthread_mutex_lock(&myMutex);
// do other things
someState = true;
// start Thread_C here
pthread_cond_signal(&myCondVar);
pthread_mutex_unlock(&myMutex);
Thread_C:
pthread_mutex_lock(&myMutex);
// can I reach this point after Thread_B releases the mutex,
// but before Thread_A re-acquires it after being signaled?
// do things that may interfere with Thread_A...
pthread_mutex_unlock(&myMutex);
Edit: The accepted answer below was chosen because it makes clear that whether or not a reader agrees with the interpretation given, there is enough ambiguity that the only safe assumption to make is that of the respondent. Note that others well-versed in C++-standard-speak may find the text totally unambiguous... I am not in that group.
There's nothing special about acquiring a mutex when awakened from pthread_cond_[timed]wait() compared to any other thread already blocked in pthread_mutex_lock() trying to acquire the same mutex.
Per the POSIX 7 pthread_cond_signal() documentation (bolding mine):
If more than one thread is blocked on a condition variable, the scheduling policy shall determine the order in which threads are unblocked. When each thread unblocked as a result of a pthread_cond_broadcast() or pthread_cond_signal() returns from its call to pthread_cond_wait() or pthread_cond_timedwait(), the thread shall own the mutex with which it called pthread_cond_wait() or pthread_cond_timedwait(). The thread(s) that are unblocked shall contend for the mutex according to the scheduling policy (if applicable), and as if each had called pthread_mutex_lock().
Acquiring the mutex after waking up from pthread_cond_[timed]wait() is required to be exactly as if the thread had called pthread_mutex_lock().
In short, any of the threads can acquire the mutex.
Related
Let's say I have two groups of threads. One group's function is to add an element to an array, and the other group's function is to remove an element from the array if the array contains the same element. The rule is that thread can't remove an element from the array if it's empty and it must wait. A monitor is used to solve this synchronization problem.
Consider a scenario in which all threads start at the same time, the consumer thread locks the mutex first and then it checks if the array is not empty, the condition is false, so it unlocks the mutex. Then the producer thread locks the mutex first, adds an elements and notifies all the waiting threads and unlocks the mutex. The question is, does the waiting thread gets the access to the mutex first after it was notified and the waiting thread can try to remove the element or the mutex is free again and any thread can lock it by chance again and the waiting thread is not finished after the condition fail, but let's say it's put back into the thread pool.
First, lets make some things clear (Includes an essence of cppreference's page about std::condition_variable):
Consumers
Consumers wait on std::condition_variable-s using the following steps:
Acquire a std::unique_lock<std::mutex>, on the same mutex as used to protect the shared variable
Execute wait, wait_for, or wait_until. The wait operations atomically release the mutex and suspend the execution of the thread.
When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is atomically reacquired. The thread should then check the condition and resume waiting if the wake up was spurious.
Producers
Producers notify the same std::condition_variable-s following these steps:
Acquire a std::mutex (typically via std::lock_guard)
Perform the modification while the lock is held
Execute notify_one or notify_all on the std::condition_variable (the lock does not need to be held for notification)
Answer
does the waiting thread gets the access to the mutex first after it was notified and the waiting thread can try to remove the element
Yes, there may be multiple consumers on the same condition, and each and every one of them may consume the single object, this is why every waiting thread should protect against spurious wake-ups using an additional logical condition (See the bold text in the consumer part). The wait methods of std::condition_variable even has a specific prototype that already includes it:
template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
When the consumer wakes up, it has already acquired the lock! So, if the condition (for example !queue->empty()) is fulfilled, it can safely consume.
This question is regarding the pthread tutorial in llnl.
Say there are three threads.
Thread 1:
pthread_mutex_lock(&mutex)
do_something...
if condition
pthread_cond_signal(&con)
pthread_mutex_unlock(&mutex)
repeat
Thread 2:
pthread_mutex_lock(&mutex)
do_something...
if condition
pthread_cond_signal(&con)
pthread_mutex_unlock(&mutex)
repeat
Thread 3:
pthread_mutex_lock(&mutex)
while(condition not holds)
pthread_cond_wait(&con)
do_something...
pthread_mutex_unlock(&mutex)
Assume that Thread1 checks that condition is satisfied and then sends signal to wake up Thread3. Finally it unlocks the mutex. But at the same time, Thread 2 is trying to lock the mutex.
My question is: is there any guarantee that Thread3 will always win in the competition?
If not then after Thread2 do_something..., the condition variable may be changed, then when Thread3 gets to lock the mutex, the condition variable is different from what it expects.
My question is: is there any guarantee that Tread3 will always win in the competition?
No such guarantees. From POSIX:
The pthread_cond_signal() function shall unblock at least one of the
threads that are blocked on the specified condition variable cond (if
any threads are blocked on cond).
If more than one thread is blocked on a condition variable, the
scheduling policy shall determine the order in which threads are
unblocked. When each thread unblocked as a result of a
pthread_cond_broadcast() or pthread_cond_signal() returns from its
call to pthread_cond_wait() or pthread_cond_timedwait(), the thread
shall own the mutex with which it called pthread_cond_wait() or
pthread_cond_timedwait(). The thread(s) that are unblocked shall
contend for the mutex according to the scheduling policy (if
applicable), and as if each had called pthread_mutex_lock().
(Emphasis mine).
If not then after Tread2 do_something..., the condition variable may be changed, then when Tread3 gets to lock the mutex, the condition variable is different from what it expects.
If the order of execution of threads matter then you probably need to rewrite your code.
There is no guarantee. Returning from pthread_cond_wait() should be treated as implying that the condition might have changed, not that it definitely has - so you need to re-check the condition, and may need to wait again. This is exactly why pthread_cond_wait() should be called within a loop that checks the condition.
I am working with condition variables and I am assuming they unlock their associated mutex on wait. Otherwise, the mutex would never be released. Yet, I can't find this information on any documentation. Consider the following code:
std::condition_variable consumerWakeMeUp;
std::mutex queueMutex;
// this locks the mutex
std::unique_lock<std::mutex> lk(queueMutex);
// going to sleep now
consumerWakeMeUp.wait(lk);
Does the "consumerWakeMeUp.wait(lk)" unlock the mutex? It must I assume otherwise the thread would hand on that mutext forever. But if anyone knows more the details I'd appreciate the input.
thank you.
never mind
"Atomically releases lock, blocks the current executing thread, and adds it to the list of threads waiting on *this. The thread will be unblocked when notify_all() or notify_one() is executed. It may also be unblocked spuriously. When unblocked, regardless of the reason, lock is reacquired and wait exits. If this function exits via exception, lock is also reacquired. (until C++14)"
I read somewhere that we should lock the mutex before calling pthread_cond_signal and unlock the mutex after calling it:
The pthread_cond_signal() routine is
used to signal (or wake up) another
thread which is waiting on the
condition variable. It should be
called after mutex is locked, and must
unlock mutex in order for
pthread_cond_wait() routine to
complete.
My question is: isn't it OK to call pthread_cond_signal or pthread_cond_broadcast methods without locking the mutex?
If you do not lock the mutex in the codepath that changes the condition and signals, you can lose wakeups. Consider this pair of processes:
Process A:
pthread_mutex_lock(&mutex);
while (condition == FALSE)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
Process B (incorrect):
condition = TRUE;
pthread_cond_signal(&cond);
Then consider this possible interleaving of instructions, where condition starts out as FALSE:
Process A Process B
pthread_mutex_lock(&mutex);
while (condition == FALSE)
condition = TRUE;
pthread_cond_signal(&cond);
pthread_cond_wait(&cond, &mutex);
The condition is now TRUE, but Process A is stuck waiting on the condition variable - it missed the wakeup signal. If we alter Process B to lock the mutex:
Process B (correct):
pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
...then the above cannot occur; the wakeup will never be missed.
(Note that you can actually move the pthread_cond_signal() itself after the pthread_mutex_unlock(), but this can result in less optimal scheduling of threads, and you've necessarily locked the mutex already in this code path due to changing the condition itself).
According to this manual :
The pthread_cond_broadcast() or
pthread_cond_signal() functions
may be called by a thread whether or not it currently owns the mutex that
threads calling pthread_cond_wait()
or pthread_cond_timedwait() have
associated with the condition variable
during their waits; however, if
predictable scheduling behavior is
required, then that mutex shall be
locked by the thread calling
pthread_cond_broadcast() or
pthread_cond_signal().
The meaning of the predictable scheduling behavior statement was explained by Dave Butenhof (author of Programming with POSIX Threads) on comp.programming.threads and is available here.
caf, in your sample code, Process B modifies condition without locking the mutex first. If Process B simply locked the mutex during that modification, and then still unlocked the mutex before calling pthread_cond_signal, there would be no problem --- am I right about that?
I believe intuitively that caf's position is correct: calling pthread_cond_signal without owning the mutex lock is a Bad Idea. But caf's example is not actually evidence in support of this position; it's simply evidence in support of the much weaker (practically self-evident) position that it is a Bad Idea to modify shared state protected by a mutex unless you have locked that mutex first.
Can anyone provide some sample code in which calling pthread_cond_signal followed by pthread_mutex_unlock yields correct behavior, but calling pthread_mutex_unlock followed by pthread_cond_signal yields incorrect behavior?
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.