I’m reading up on pthread.h; the condition variable related functions (like pthread_cond_wait(3)) require a mutex as an argument. Why? As far as I can tell, I’m going to be creating a mutex just to use as that argument? What is that mutex supposed to do?
It's just the way that condition variables are (or were originally) implemented.
The mutex is used to protect the condition variable itself. That's why you need it locked before you do a wait.
The wait will "atomically" unlock the mutex, allowing others access to the condition variable (for signalling). Then when the condition variable is signalled or broadcast to, one or more of the threads on the waiting list will be woken up and the mutex will be magically locked again for that thread.
You typically see the following operation with condition variables, illustrating how they work. The following example is a worker thread which is given work via a signal to a condition variable.
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
do the work.
unlock mutex.
clean up.
exit thread.
The work is done within this loop provided that there is some available when the wait returns. When the thread has been flagged to stop doing work (usually by another thread setting the exit condition then kicking the condition variable to wake this thread up), the loop will exit, the mutex will be unlocked and this thread will exit.
The code above is a single-consumer model as the mutex remains locked while the work is being done. For a multi-consumer variation, you can use, as an example:
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
copy work to thread local storage.
unlock mutex.
do the work.
lock mutex.
unlock mutex.
clean up.
exit thread.
which allows other consumers to receive work while this one is doing work.
The condition variable relieves you of the burden of polling some condition instead allowing another thread to notify you when something needs to happen. Another thread can tell that thread that work is available as follows:
lock mutex.
flag work as available.
signal condition variable.
unlock mutex.
The vast majority of what are often erroneously called spurious wakeups was generally always because multiple threads had been signalled within their pthread_cond_wait call (broadcast), one would return with the mutex, do the work, then re-wait.
Then the second signalled thread could come out when there was no work to be done. So you had to have an extra variable indicating that work should be done (this was inherently mutex-protected with the condvar/mutex pair here - other threads needed to lock the mutex before changing it however).
It was technically possible for a thread to return from a condition wait without being kicked by another process (this is a genuine spurious wakeup) but, in all my many years working on pthreads, both in development/service of the code and as a user of them, I never once received one of these. Maybe that was just because HP had a decent implementation :-)
In any case, the same code that handled the erroneous case also handled genuine spurious wakeups as well since the work-available flag would not be set for those.
A condition variable is quite limited if you could only signal a condition, usually you need to handle some data that's related to to condition that was signalled. Signalling/wakeup have to be done atomically in regards to achieve that without introducing race conditions, or be overly complex
pthreads can also give you , for rather technical reasons, a spurious wakeup . That means you need to check a predicate, so you can be sure the condition actually was signalled - and distinguish that from a spurious wakeup. Checking such a condition in regards to waiting for it need to be guarded - so a condition variable needs a way to atomically wait/wake up while locking/unlocking a mutex guarding that condition.
Consider a simple example where you're notified that some data are produced. Maybe another thread made some data that you want, and set a pointer to that data.
Imagine a producer thread giving some data to another consumer thread through a 'some_data'
pointer.
while(1) {
pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
char *data = some_data;
some_data = NULL;
handle(data);
}
you'd naturally get a lot of race condition, what if the other thread did some_data = new_data right after you got woken up, but before you did data = some_data
You cannot really create your own mutex to guard this case either .e.g
while(1) {
pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
pthread_mutex_lock(&mutex);
char *data = some_data;
some_data = NULL;
pthread_mutex_unlock(&mutex);
handle(data);
}
Will not work, there's still a chance of a race condition in between waking up and grabbing the mutex. Placing the mutex before the pthread_cond_wait doesn't help you, as you will now
hold the mutex while waiting - i.e. the producer will never be able to grab the mutex.
(note, in this case you could create a second condition variable to signal the producer that you're done with some_data - though this will become complex, especially so if you want many producers/consumers.)
Thus you need a way to atomically release/grab the mutex when waiting/waking up from the condition. That's what pthread condition variables does, and here's what you'd do:
while(1) {
pthread_mutex_lock(&mutex);
while(some_data == NULL) { // predicate to acccount for spurious wakeups,would also
// make it robust if there were several consumers
pthread_cond_wait(&cond,&mutex); //atomically lock/unlock mutex
}
char *data = some_data;
some_data = NULL;
pthread_mutex_unlock(&mutex);
handle(data);
}
(the producer would naturally need to take the same precautions, always guarding 'some_data' with the same mutex, and making sure it doesn't overwrite some_data if some_data is currently != NULL)
POSIX condition variables are stateless. So it is your responsibility to maintain the state. Since the state will be accessed by both threads that wait and threads that tell other threads to stop waiting, it must be protected by a mutex. If you think you can use condition variables without a mutex, then you haven't grasped that condition variables are stateless.
Condition variables are built around a condition. Threads that wait on a condition variable are waiting for some condition. Threads that signal condition variables change that condition. For example, a thread might be waiting for some data to arrive. Some other thread might notice that the data has arrived. "The data has arrived" is the condition.
Here's the classic use of a condition variable, simplified:
while(1)
{
pthread_mutex_lock(&work_mutex);
while (work_queue_empty()) // wait for work
pthread_cond_wait(&work_cv, &work_mutex);
work = get_work_from_queue(); // get work
pthread_mutex_unlock(&work_mutex);
do_work(work); // do that work
}
See how the thread is waiting for work. The work is protected by a mutex. The wait releases the mutex so that another thread can give this thread some work. Here's how it would be signalled:
void AssignWork(WorkItem work)
{
pthread_mutex_lock(&work_mutex);
add_work_to_queue(work); // put work item on queue
pthread_cond_signal(&work_cv); // wake worker thread
pthread_mutex_unlock(&work_mutex);
}
Notice that you need the mutex to protect the work queue. Notice that the condition variable itself has no idea whether there's work or not. That is, a condition variable must be associated with a condition, that condition must be maintained by your code, and since it's shared among threads, it must be protected by a mutex.
Not all condition variable functions require a mutex: only the waiting operations do. The signal and broadcast operations do not require a mutex. A condition variable also is not permanently associated with a specific mutex; the external mutex does not protect the condition variable. If a condition variable has internal state, such as a queue of waiting threads, this must be protected by an internal lock inside the condition variable.
The wait operations bring together a condition variable and a mutex, because:
a thread has locked the mutex, evaluated some expression over shared variables and found it to be false, such that it needs to wait.
the thread must atomically move from owning the mutex, to waiting on the condition.
For this reason, the wait operation takes as arguments both the mutex and condition: so that it can manage the atomic transfer of a thread from owning the mutex to waiting, so that the thread does not fall victim to the lost wake up race condition.
A lost wakeup race condition will occur if a thread gives up a mutex, and then waits on a stateless synchronization object, but in a way which is not atomic: there exists a window of time when the thread no longer has the lock, and has not yet begun waiting on the object. During this window, another thread can come in, make the awaited condition true, signal the stateless synchronization and then disappear. The stateless object doesn't remember that it was signaled (it is stateless). So then the original thread goes to sleep on the stateless synchronization object, and does not wake up, even though the condition it needs has already become true: lost wakeup.
The condition variable wait functions avoid the lost wake up by making sure that the calling thread is registered to reliably catch the wakeup before it gives up the mutex. This would be impossible if the condition variable wait function did not take the mutex as an argument.
I do not find the other answers to be as concise and readable as this page. Normally the waiting code looks something like this:
mutex.lock()
while(!check())
condition.wait(mutex) # atomically unlocks mutex and sleeps. Calls
# mutex.lock() once the thread wakes up.
mutex.unlock()
There are three reasons to wrap the wait() in a mutex:
without a mutex another thread could signal() before the wait() and we'd miss this wake up.
normally check() is dependent on modification from another thread, so you need mutual exclusion on it anyway.
to ensure that the highest priority thread proceeds first (the queue for the mutex allows the scheduler to decide who goes next).
The third point is not always a concern - historical context is linked from the article to this conversation.
Spurious wake-ups are often mentioned with regard to this mechanism (i.e. the waiting thread is awoken without signal() being called). However, such events are handled by the looped check().
Condition variables are associated with a mutex because it is the only way it can avoid the race that it is designed to avoid.
// incorrect usage:
// thread 1:
while (notDone) {
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable
pthread_mutex_unlock(&mutex);
if (ready) {
doWork();
} else {
pthread_cond_wait(&cond1); // invalid syntax: this SHOULD have a mutex
}
}
// signalling thread
// thread 2:
prepareToRunThread1();
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond1);
Now, lets look at a particularly nasty interleaving of these operations
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable;
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond1);
if (ready) {
pthread_cond_wait(&cond1); // uh o!
At this point, there is no thread which is going to signal the condition variable, so thread1 will wait forever, even though the protectedReadyToRunVariable says it's ready to go!
The only way around this is for condition variables to atomically release the mutex while simultaneously starting to wait on the condition variable. This is why the cond_wait function requires a mutex
// correct usage:
// thread 1:
while (notDone) {
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable
if (ready) {
pthread_mutex_unlock(&mutex);
doWork();
} else {
pthread_cond_wait(&mutex, &cond1);
}
}
// signalling thread
// thread 2:
prepareToRunThread1();
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_cond_signal(&mutex, &cond1);
pthread_mutex_unlock(&mutex);
The mutex is supposed to be locked when you call pthread_cond_wait; when you call it it atomically both unlocks the mutex and then blocks on the condition. Once the condition is signaled it atomically locks it again and returns.
This allows the implementation of predictable scheduling if desired, in that the thread that would be doing the signalling can wait until the mutex is released to do its processing and then signal the condition.
It appears to be a specific design decision rather than a conceptual need.
Per the pthreads docs the reason that the mutex was not separated is that there is a significant performance improvement by combining them and they expect that because of common race conditions if you don't use a mutex, it's almost always going to be done anyway.
https://linux.die.net/man/3/pthread_cond_wait
Features of Mutexes and Condition Variables
It had been suggested that the mutex acquisition and release be
decoupled from condition wait. This was rejected because it is the
combined nature of the operation that, in fact, facilitates realtime
implementations. Those implementations can atomically move a
high-priority thread between the condition variable and the mutex in a
manner that is transparent to the caller. This can prevent extra
context switches and provide more deterministic acquisition of a mutex
when the waiting thread is signaled. Thus, fairness and priority
issues can be dealt with directly by the scheduling discipline.
Furthermore, the current condition wait operation matches existing
practice.
There are a tons of exegeses about that, yet I want to epitomize it with an example following.
1 void thr_child() {
2 done = 1;
3 pthread_cond_signal(&c);
4 }
5 void thr_parent() {
6 if (done == 0)
7 pthread_cond_wait(&c);
8 }
What's wrong with the code snippet? Just ponder somewhat before going ahead.
The issue is genuinely subtle. If the parent invokes
thr_parent() and then vets the value of done, it will see that it is 0 and
thus try to go to sleep. But just before it calls wait to go to sleep, the parent
is interrupted between lines of 6-7, and the child runs. The child changes the state variable
done to 1 and signals, but no thread is waiting and thus no thread is
woken. When the parent runs again, it sleeps forever, which is really egregious.
What if they are carried out while acquired locks individually?
I made an exercice in class if you want a real example of condition variable :
#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
#include "unistd.h"
int compteur = 0;
pthread_cond_t varCond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex_compteur;
void attenteSeuil(arg)
{
pthread_mutex_lock(&mutex_compteur);
while(compteur < 10)
{
printf("Compteur : %d<10 so i am waiting...\n", compteur);
pthread_cond_wait(&varCond, &mutex_compteur);
}
printf("I waited nicely and now the compteur = %d\n", compteur);
pthread_mutex_unlock(&mutex_compteur);
pthread_exit(NULL);
}
void incrementCompteur(arg)
{
while(1)
{
pthread_mutex_lock(&mutex_compteur);
if(compteur == 10)
{
printf("Compteur = 10\n");
pthread_cond_signal(&varCond);
pthread_mutex_unlock(&mutex_compteur);
pthread_exit(NULL);
}
else
{
printf("Compteur ++\n");
compteur++;
}
pthread_mutex_unlock(&mutex_compteur);
}
}
int main(int argc, char const *argv[])
{
int i;
pthread_t threads[2];
pthread_mutex_init(&mutex_compteur, NULL);
pthread_create(&threads[0], NULL, incrementCompteur, NULL);
pthread_create(&threads[1], NULL, attenteSeuil, NULL);
pthread_exit(NULL);
}
Related
Let's say I had 4 threads, a producer and three consumers, a single mutex and a single condition variable, every consumer runs the same function that does the below:
mutexlock(mutex)
signal[i] = 1;
while(signal[i] == 1) {
condwait(cond, mutex)
}
mutexunlock(mutex)
And the producer does the below
if(signal == 1)
{
set 0 - atomically using CAS
mutexlock(mutex)
condbroadcast(cond)
mutexunlock(mutex)
}
Let's say if more than one consumer were in that lock, wouldn't they fight for the cond variable? Should I create one for each thread or can p_thread condition variables be shared accross multiple threads without any race conditions?
When you create a muti-thread program,they share the resource signal[i] and all the three thread will compete for the resources.When signal[i] == 0,the threads which didn't get the resource will be put into the queue of the condition variable.And when you send a broadcast,all the waiting threads in the condition variable will weak up and compete for the resouce.Here is a tourial for muti-thread beginner in C.
Semantic of pthread_cond_wait is to release acquired mutex and block on conditional variable. When signal arrives, block is released, then pthread_cond_wait acquires the lock on mutex.
So, in your case, when you use pthread_cond_broadcast all threads blocked on conditional will move past this point, but after that one of them will be granted lock on mutex. Which one? It depends on the order the scheduler wakes them up after being unblocked and the pthread implementation in case two or more threads try to acquire the lock at the some moment. It's safe to consider it's random.
If you replace pthread_cond_broadcast with pthread_cond_signal, the signal will be delivered to some threads. Yes, it is expected to be one, but sometimes more than one can be released from conditional variable. Still, the thread (or threads) to deliver signal to will be chosen by scheduler. And if more than one is waked up from cond waiting, they will fight for the mutex. As previously - you can consider the result as random.
Let's look into documentation:
If more than one thread is blocked on a condition variable, the scheduling policy shall determine the order in which threads are unblocked.
On a multi-processor, it may be impossible for an implementation of pthread_cond_signal() to avoid the unblocking of more than one thread blocked on a condition variable.
BTW, I am quite curious. There are several questions about conditional variables recently (are you guys all doing a project for your uni or what?) and in every question I have seen in last 24 hours I have seen a following pattern for signalling:
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond); /* or signal */
pthread_mutex_unlock(&mutex);
when waiting threads have:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond,&mutex);
/* do something */
pthread_mutex_unlock(&mutex);
What's the reason behind that?
Waiting threads wait on cond, mutex is released. So signalling thread acquires lock on mutex, signals other threads. In this very moment they - still being inside the pthread_cond_wait progress past the cond blockade, then they try to acquire the lock on mutex. And, of course, they cannot, because the lock is hold by signalling thread. Then, signalling thread releases mutex and waiting threads can finally process by acquiring - one by one - the mutex.
For signalling writer and waiting consumers this pattern should be as below.
For writer:
while(loop_condition) {
prepare_data() /* it could be a long process */
lock(&mutex);
add_data_to_queue(); /* fast, inside critical section */
unlock(&mutex);
signal(&cond); /* or broadcast */
}
For consumers:
while(consumer_loop_condition) {
lock(&mutex);
while(!data_ready_to_process()) {
wait(&cond,&mutex);
}
fetch_data(); /* fast, still inside critical section */
unlock(&mutex);
if(got_data) {
process_data(); /* could be a long process */
}
}
Please see also this answer for some more explanation on cond/mutexes and some example code to play with.
This question concerns the pthread API for Posix systems.
My understanding is that when waiting for a conditional variable, or more specifically a pthread_cond_t, the flow goes something like this.
// imagine the mutex is named mutex and the conditional variable is named cond
// first we lock the mutex to prevent race conditions
pthread_mutex_lock(&mutex);
// then we wait for the conditional variable, releasing the mutex
pthread_cond_wait(&cond, &mutex);
// after we're done waiting we own the mutex again have to release it
pthread_mutex_unlock(&mutex);
In this example we stop waiting for the mutex when some other thread follows a procedure like this.
// lock the mutex to prevent race conditions
pthread_mutex_lock(&mutex);
// signal the conditional variable, giving up control of the mutex
pthread_cond_signal(&cond);
My understanding is that if multiple threads are waiting some kind of scheduling policy will be applied, and whichever thread is unblocked also gets back the associated mutex.
Now what I don't understand is what happens when some thread calls pthread_cond_broadcast(&cond) to awake all of the threads waiting on the conditional variable.
Does only one thread get to own the mutex? Do I need to wait in a fundamentally different manner when waiting for a broadcast than when waiting for a signal (i.e. by not calling pthread_mutex_unlock unless I can confirm this thread acquired the mutex)? Or am I wrong in my whole understanding of how the mutex/cond relationship works?
Most importantly, if (as I think is probably the case) pthread_cond_broadcast causes threads to compete for the associated mutex as if they had all tried to lock it, does that mean only one thread will really wake up?
When some thread calls pthread_cond_broadcast while holding the mutex, it holds the mutex. Which means that once pthread_cond_broadcast returns, it still owns the mutex.
The other threads will all wake up, try to lock the mutex, then go to sleep to wait for the mutex to become available.
If you call pthread_cond_broadcast while not holding the mutex, then one of the other threads will be able to lock the mutex immediately. All the others will have to wait to lock the mutex.
I m using pthread_cond_wait(&cond_t, &mutex); in my program and I m wondering why this function need as a second parameter a mutex variable.
Does the pthread_cond_wait() unlock the mutex at the beggining (beggining of the execution pthread_cond_wait()) and then locked when it finish (just before leaving pthread_cond_wait())?
There are many text on the subject of condition variables and their usage, so I'll not bore you with a ton of ugly details. The reason they exist at all is to allow you to notify change in a predicate state. The following are critical in understanding proper use of condition variables and their mutex association:
pthread_cond_wait() simultaneously unlocks the mutex and begins waiting for the condition variable to be signalled. thus you must always have ownership of the mutex before invoking it.
pthread_cond_wait() returns with the mutex locked, thus you must unlock the mutex to allow its use somewhere else when finished with it. Whether the return happened because the condition variable was signalled or not isn't relevant. You still need to check your predicate regardless to account for potential spurious wakeups.
The purpose of the mutex is not to protect the condition variable; it is to protect the predicate on which the condition variable is being used as a signaling mechanism. This is hands-down the most often misunderstood idiom of pthread condition variables and their mutexes. The condition variable doesn't need mutual exclusion protection; the predicate data does. Think of the predicate as an outside-state which is being monitored by the users of the condition-variable/mutex pair.
For example, a trivial yet obviously wrong piece of code to wait for a boolean flag fSet:
bool fSet = false;
int WaitForTrue()
{
while (!fSet)
{
sleep(n);
}
}
I should be obvious the main problem is the predicate, fSet, is not protected at all. Many things can go wrong here. Ex: From the time you evaluate the while-conditon until the time you begin waiting (or spinning, or whatever) the value may have changed. If that change notification is somehow missed, you're needlessly waiting.
We can change this a little so at least the predicate is protected somehow. Mutual exclusion in both modifying and evaluating the predicate is easily provided with (what else) a mutex.
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
bool fSet = false;
int WaitForTrue()
{
pthread_mutex_lock(&mtx);
while (!fSet)
sleep(n);
pthread_mutex_unlock(&mtx);
}
Well, that seems simple enough.. Now we never evaluate the predicate without first getting exclusive access to it (by latching the mutex). But this is still a major problem. We latched the mutex, but we never release it until our loop is finished. If everyone else plays by the rules and waits for the mutex lock before evaluation or modification of fSet, they're never be able to do so until we give up the mutex. The only "someone" that can do that in this case is us.
So what about adding still more layers to this. Will this work?
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
bool fSet = false;
int WaitForTrue()
{
pthread_mutex_lock(&mtx);
while (!fSet)
{
pthread_mutex_unlock(&mtx);
// XXXXX
sleep(n);
// YYYYY
pthread_mutex_lock(&mtx);
}
pthread_mutex_unlock(&mtx);
}
Well, yes it will "work", but still is not much better. The period between XXXXX and YYYYY we don't own the mutex (which is ok, since we're not checking or modifying fSet anyway). But anytime during that period some other thread can (a) obtain the mutex, (b) modify fSet, and (c) release the mutex, and we won't know a thing about it until we finish our sleep(), once-again obtain the mutex lock, and loop around for another check.
There has to be a better way. Somehow there should be a way that we can release the mutex and begin waiting for some sort of signal that tells us a change in the predicate may have happened. Equally important, when we receive that signal and return to our code, we should already own the lock that grants us access to check the predicate data. This is exactly what a condition-variable is designed to provide.
The Condition Variable In Action
Enter the condition-variable + mutex pair. The mutex protects access to changing or checking the predicate, while the condition variable sets up a system of monitoring a change, and more importantly, doing so atomically (as far as you're concerned, anyway) with the predicate mutual exclusion:
int WaitForPredicate()
{
// lock mutex (means:lock access to the predicate)
pthread_mutex_lock(&mtx);
// we can safely check this, since no one else should be
// changing it unless they have the mutex, which they don't
// because we just locked it.
while (!predicate)
{
// predicate not met, so begin waiting for notification
// it has been changed *and* release access to change it
// to anyone wanting to by unlatching the mutex, doing
// both (start waiting and unlatching) atomically
pthread_cond_wait(&cv,&mtx);
// upon arriving here, the above returns with the mutex
// latched (we own it). The predicate *may* be true, and
// we'll be looping around to see if it is, but we can
// safely do so because we own the mutex coming out of
// the cv-wait call.
}
// we still own the mutex here. further, we have assessed the
// predicate is true (thus how we broke the loop).
// take whatever action needed.
// You *must* release the mutex before we leave. Remember, we
// still own it even after the code above.
pthread_mutex_unlock(&mtx);
}
For some other thread to signal the loop above, there are several ways to do it, the two most popular below:
pthread_mutex_lock(&mtx);
TODO: change predicate state here as needed.
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cv);
Another way...
pthread_mutex_lock(&mtx);
TODO: change predicate state here as needed.
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mtx);
Each has different intrinsic behavior and I invite you to do some homework on those differences and determine which is more appropriate for specific circumstances. The former provides better program flow at the expense of introducing potentially unwarranted wake-ups. The latter reduces those wake-ups but at the price of less context synergy. Either will work in our sample, and you can experiment with how each affects your waiting loops. Regardless, one thing paramount, and both methods fulfill this mandate:
Never change, nor check, the predicate condition unless the mutex is locked. Ever.
Simple Monitor Thread
This type of operation is common in a monitor thread that acts on a specific predicate condition, which (sans' error checking) typically looks something like this:
void* monitor_proc(void *pv)
{
// acquire mutex ownership
// (which means we own change-control to the predicate)
pthread_mutex_lock(&mtx);
// heading into monitor loop, we own the predicate mutex
while (true)
{
// safe to check; we own the mutex
while (!predicate)
pthread_cond_wait(&cv, &mtx);
// TODO: the cv has been signalled. our predicate data should include
// data to signal a break-state to exit this loop and finish the proc,
// as well as data that we may check for other processing.
}
// we still own the mutex. remember to release it on exit
pthread_mutex_unlock(&mtx);
return pv;
}
A More Complex Monitor Thread
Modifying this basic form to account for a notification system that doesn't require you to keep the mutex latched once you've picked up the notification becomes a little more involved, but not by very much. Below is a monitor proc that does not keep the mutex latched during regular processing once we've established we've been served (so to speak).
void* monitor_proc(void *pv)
{
// acquire mutex ownership
// (which means we own change-control to the predicate)
pthread_mutex_lock(&mtx);
// heading into monitor loop, we own the predicate mutex
while (true)
{
// check predicate
while (!predicate)
pthread_cond_wait(&cv, &mtx);
// some state that is part of the predicate to
// inform us we're finished
if (break-state)
break;
// TODO: perform latch-required work here.
// unlatch the mutex to do our predicate-independant work.
pthread_mutex_unlock(&mtx);
// TODO: perform no-latch-required work here.
// re-latch mutex prior to heading into wait
pthread_mutex_lock(&mtx);
}
// we still own the mutex. remember to release it on exit
pthread_mutex_unlock(&mtx);
return pv;
}
Where would someone use something like that ? Well, suppose your "predicate" is the "state" of a work queue as well as some flag to tell you to stop looping and exit. Upon receiving the notification that something is "different", you check to see if you should continue executing your loop, and deciding you should continue, pop some data off the queue. Modifying the queue requires the mutex be latched (remember, its "state" is part of our predicate). Once we have popped our data, we have it locally and can process it independent of the queue state, so we release the mutex, do our thing, then require the mutex for the next go-around. There are many ways to code the above concept, including judicious use of pthread_cond_broadcast, etc. But the basic form is hopefully understandable.
This turned out to be considerably longer than I had hoped, but this is a major hurdle for people learning pthread-programming, and I feel it is worth the extra time/effort. I hope you got something out of it.
When the first thread calls pthread_cond_wait(&cond_t, &mutex); it releases the mutex and it waits till condition cond_t is signaled as complete and mutex is available.
So when pthread_cond_signal is called in the other thread, it doesn't "wake up" the thread that waits yet. mutex must be unlocked first, only then there is a chance that first thread will get a lock, which means that "upon successful return of pthread_cond_wait mutex shall have been locked and shall be owned by the calling thread."
yes it unlocks, waits for the condition to be fulfilled and then waits till it can reaquire the passed mutex.
Regarding this:
How To Use Condition Variable
Say we have number of consumer threads that execute such code (copied from the referenced page):
while (TRUE) {
s = pthread_mutex_lock(&mtx);
while (avail == 0) { /* Wait for something to consume */
s = pthread_cond_wait(&cond, &mtx);
}
while (avail > 0) { /* Consume all available units */
avail--;
}
s = pthread_mutex_unlock(&mtx);
}
I assume that scenario here is: main thread calls pthread_cond_signal() to tell consumer threads to do some work.
As I understand it - subsequent threads call pthread_mutex_lock() and then pthread_cond_wait() (which atomically unlocks the mutex). By now none of the consumer threads is claiming the mutex, they all wait on pthread_cond_wait().
When the main thread calls pthread_cond_signal(), following the manpage, at least one thread is waken up. When any of them returns from pthread_cond_wait() it automatically claims the mutex.
So my question is: what happens now regarding the provided example code? Namely, what does the thread that lost the contest for the mutex do now?
(AFAICT the thread that won the mutex, should run the rest of the code and release the mutex. The one that lost should be stuck waiting on the mutex - somewhere in the 1st nested while loop - while the winner holds it and after it's been released start blocking on pthread_cond_wait() beacuse the while (avail == 0) will be satisfied by then. Am I correct?)
Note that pthread_cond_signal() is generally intended to wake up only one waiting thread (that's all that it guarantees). But it could wake more 'accidentally'. The while (avail > 0) loop performs two functions:
it allows the one thread guaranteed to be woken up to consume all queued work units
it prevents additional 'accidentally' awakened threads from assuming that there's work to be done, when there might not be since the initial thread would have handled all of them.
It also prevents a race condition where a work unit might have been placed on the queue after the while (avail > 0) has completed, but before the worker thread has waited on the condition again - but that race is also handled by the if test just before calling pthread_cond_wait().
Basically when a thread is awakened, all it knows is that there might be work units for it to consume, but there might not (another thread might have consumed them).
So the sequence of events that occurs when pthread_cond_signal() is called is:
the system will wake one or more threads waiting on the condition
all the threads that are awakened will then try to acquire the mutex - only one of them can acquire it at any particular moment, since that's the purpose of a mutex
that thread will then proceed, perform the work in the while (avail > 0) loop, then will release the mutex
at that point one of the other threads that were previously woken up will acquire the mutex and work the same loop, then release the mutex. Generally, there will be no work units available anymore (since the first thread would have consumed all of them), but if another thread had added an additional unit (or more), then this thread would handle that work
the next thread will acquire the mutex and perform that same set of logic
pthread_cond_wait() has to acquire given mutex once signaled/woken up. If another thread wins that race, the function blocks until the mutex is released. So from the application point of view it doesn't return until current thread holds the mutex. The wait is always done in a loop (while (avail == 0) { ... above) to make sure that application condition we are waiting for still holds (buffer not empty, more work available, etc.)
Hope this helps.
The thread that lost the contest wakes up once the mutex is unlocked, checks the condition again, then goes to sleep on the condition variable.
When any of them returns from pthread_cond_wait() it automatically claims the mutex.
Ah, but it doesn't. Not "automatically", that is, depending on what "automatically" means. You might be confused by the "atomic" semantics of pthread_cond_wait; but that semantics is played out on the entry side: a thread is somehow registered for waiting on the condition before giving up the mutex, so that there isn't any window during which the thread no longer has the mutex, and is not yet waiting on the variable.
Each thread which returns from pthread_cond_wait has to acquire the mutex and therefore contend for it. Those which lose the race for the mutex have to block on the mutex, similarly as if they called pthread_mutex_lock.
The way the mutex is acquired on exit from pthread_cond_wait can be modeled as a regular pthread_mutex_lock operation. Essentially, the threads have to queue up on the mutex in order to exit. Each thread which acquires the mutex then returns from the function; the others have to wait until that thread gives up the mutex before they are allowed to return.
No thread woken up by the signal gets the mutex "automatically", in the sense of somehow being transferred ownership due to special eligibility. Firstly, on a multiprocessor, a woken thread can lose the race to a thread already running on another processor which snatches the mutex, if it is available, or else queue to wait on the mutex ahead of the thread which received the signal. Secondly, the thread which calls pthread_cond_signal may itself not have given up the mutex, and may continue to hold it indefinitely, which means that all the woken threads will queue up on a mutex lock operation and none will emerge from pthread_mutex_lock until that thread gives up the mutex.
All that is "automatic" is that the pthread_cond_wait operation doesn't return until acquiring the mutex again, and so the application doesn't have to take the step to acquire the mutex.
I’m reading up on pthread.h; the condition variable related functions (like pthread_cond_wait(3)) require a mutex as an argument. Why? As far as I can tell, I’m going to be creating a mutex just to use as that argument? What is that mutex supposed to do?
It's just the way that condition variables are (or were originally) implemented.
The mutex is used to protect the condition variable itself. That's why you need it locked before you do a wait.
The wait will "atomically" unlock the mutex, allowing others access to the condition variable (for signalling). Then when the condition variable is signalled or broadcast to, one or more of the threads on the waiting list will be woken up and the mutex will be magically locked again for that thread.
You typically see the following operation with condition variables, illustrating how they work. The following example is a worker thread which is given work via a signal to a condition variable.
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
do the work.
unlock mutex.
clean up.
exit thread.
The work is done within this loop provided that there is some available when the wait returns. When the thread has been flagged to stop doing work (usually by another thread setting the exit condition then kicking the condition variable to wake this thread up), the loop will exit, the mutex will be unlocked and this thread will exit.
The code above is a single-consumer model as the mutex remains locked while the work is being done. For a multi-consumer variation, you can use, as an example:
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
copy work to thread local storage.
unlock mutex.
do the work.
lock mutex.
unlock mutex.
clean up.
exit thread.
which allows other consumers to receive work while this one is doing work.
The condition variable relieves you of the burden of polling some condition instead allowing another thread to notify you when something needs to happen. Another thread can tell that thread that work is available as follows:
lock mutex.
flag work as available.
signal condition variable.
unlock mutex.
The vast majority of what are often erroneously called spurious wakeups was generally always because multiple threads had been signalled within their pthread_cond_wait call (broadcast), one would return with the mutex, do the work, then re-wait.
Then the second signalled thread could come out when there was no work to be done. So you had to have an extra variable indicating that work should be done (this was inherently mutex-protected with the condvar/mutex pair here - other threads needed to lock the mutex before changing it however).
It was technically possible for a thread to return from a condition wait without being kicked by another process (this is a genuine spurious wakeup) but, in all my many years working on pthreads, both in development/service of the code and as a user of them, I never once received one of these. Maybe that was just because HP had a decent implementation :-)
In any case, the same code that handled the erroneous case also handled genuine spurious wakeups as well since the work-available flag would not be set for those.
A condition variable is quite limited if you could only signal a condition, usually you need to handle some data that's related to to condition that was signalled. Signalling/wakeup have to be done atomically in regards to achieve that without introducing race conditions, or be overly complex
pthreads can also give you , for rather technical reasons, a spurious wakeup . That means you need to check a predicate, so you can be sure the condition actually was signalled - and distinguish that from a spurious wakeup. Checking such a condition in regards to waiting for it need to be guarded - so a condition variable needs a way to atomically wait/wake up while locking/unlocking a mutex guarding that condition.
Consider a simple example where you're notified that some data are produced. Maybe another thread made some data that you want, and set a pointer to that data.
Imagine a producer thread giving some data to another consumer thread through a 'some_data'
pointer.
while(1) {
pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
char *data = some_data;
some_data = NULL;
handle(data);
}
you'd naturally get a lot of race condition, what if the other thread did some_data = new_data right after you got woken up, but before you did data = some_data
You cannot really create your own mutex to guard this case either .e.g
while(1) {
pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
pthread_mutex_lock(&mutex);
char *data = some_data;
some_data = NULL;
pthread_mutex_unlock(&mutex);
handle(data);
}
Will not work, there's still a chance of a race condition in between waking up and grabbing the mutex. Placing the mutex before the pthread_cond_wait doesn't help you, as you will now
hold the mutex while waiting - i.e. the producer will never be able to grab the mutex.
(note, in this case you could create a second condition variable to signal the producer that you're done with some_data - though this will become complex, especially so if you want many producers/consumers.)
Thus you need a way to atomically release/grab the mutex when waiting/waking up from the condition. That's what pthread condition variables does, and here's what you'd do:
while(1) {
pthread_mutex_lock(&mutex);
while(some_data == NULL) { // predicate to acccount for spurious wakeups,would also
// make it robust if there were several consumers
pthread_cond_wait(&cond,&mutex); //atomically lock/unlock mutex
}
char *data = some_data;
some_data = NULL;
pthread_mutex_unlock(&mutex);
handle(data);
}
(the producer would naturally need to take the same precautions, always guarding 'some_data' with the same mutex, and making sure it doesn't overwrite some_data if some_data is currently != NULL)
POSIX condition variables are stateless. So it is your responsibility to maintain the state. Since the state will be accessed by both threads that wait and threads that tell other threads to stop waiting, it must be protected by a mutex. If you think you can use condition variables without a mutex, then you haven't grasped that condition variables are stateless.
Condition variables are built around a condition. Threads that wait on a condition variable are waiting for some condition. Threads that signal condition variables change that condition. For example, a thread might be waiting for some data to arrive. Some other thread might notice that the data has arrived. "The data has arrived" is the condition.
Here's the classic use of a condition variable, simplified:
while(1)
{
pthread_mutex_lock(&work_mutex);
while (work_queue_empty()) // wait for work
pthread_cond_wait(&work_cv, &work_mutex);
work = get_work_from_queue(); // get work
pthread_mutex_unlock(&work_mutex);
do_work(work); // do that work
}
See how the thread is waiting for work. The work is protected by a mutex. The wait releases the mutex so that another thread can give this thread some work. Here's how it would be signalled:
void AssignWork(WorkItem work)
{
pthread_mutex_lock(&work_mutex);
add_work_to_queue(work); // put work item on queue
pthread_cond_signal(&work_cv); // wake worker thread
pthread_mutex_unlock(&work_mutex);
}
Notice that you need the mutex to protect the work queue. Notice that the condition variable itself has no idea whether there's work or not. That is, a condition variable must be associated with a condition, that condition must be maintained by your code, and since it's shared among threads, it must be protected by a mutex.
Not all condition variable functions require a mutex: only the waiting operations do. The signal and broadcast operations do not require a mutex. A condition variable also is not permanently associated with a specific mutex; the external mutex does not protect the condition variable. If a condition variable has internal state, such as a queue of waiting threads, this must be protected by an internal lock inside the condition variable.
The wait operations bring together a condition variable and a mutex, because:
a thread has locked the mutex, evaluated some expression over shared variables and found it to be false, such that it needs to wait.
the thread must atomically move from owning the mutex, to waiting on the condition.
For this reason, the wait operation takes as arguments both the mutex and condition: so that it can manage the atomic transfer of a thread from owning the mutex to waiting, so that the thread does not fall victim to the lost wake up race condition.
A lost wakeup race condition will occur if a thread gives up a mutex, and then waits on a stateless synchronization object, but in a way which is not atomic: there exists a window of time when the thread no longer has the lock, and has not yet begun waiting on the object. During this window, another thread can come in, make the awaited condition true, signal the stateless synchronization and then disappear. The stateless object doesn't remember that it was signaled (it is stateless). So then the original thread goes to sleep on the stateless synchronization object, and does not wake up, even though the condition it needs has already become true: lost wakeup.
The condition variable wait functions avoid the lost wake up by making sure that the calling thread is registered to reliably catch the wakeup before it gives up the mutex. This would be impossible if the condition variable wait function did not take the mutex as an argument.
I do not find the other answers to be as concise and readable as this page. Normally the waiting code looks something like this:
mutex.lock()
while(!check())
condition.wait(mutex) # atomically unlocks mutex and sleeps. Calls
# mutex.lock() once the thread wakes up.
mutex.unlock()
There are three reasons to wrap the wait() in a mutex:
without a mutex another thread could signal() before the wait() and we'd miss this wake up.
normally check() is dependent on modification from another thread, so you need mutual exclusion on it anyway.
to ensure that the highest priority thread proceeds first (the queue for the mutex allows the scheduler to decide who goes next).
The third point is not always a concern - historical context is linked from the article to this conversation.
Spurious wake-ups are often mentioned with regard to this mechanism (i.e. the waiting thread is awoken without signal() being called). However, such events are handled by the looped check().
Condition variables are associated with a mutex because it is the only way it can avoid the race that it is designed to avoid.
// incorrect usage:
// thread 1:
while (notDone) {
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable
pthread_mutex_unlock(&mutex);
if (ready) {
doWork();
} else {
pthread_cond_wait(&cond1); // invalid syntax: this SHOULD have a mutex
}
}
// signalling thread
// thread 2:
prepareToRunThread1();
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond1);
Now, lets look at a particularly nasty interleaving of these operations
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable;
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond1);
if (ready) {
pthread_cond_wait(&cond1); // uh o!
At this point, there is no thread which is going to signal the condition variable, so thread1 will wait forever, even though the protectedReadyToRunVariable says it's ready to go!
The only way around this is for condition variables to atomically release the mutex while simultaneously starting to wait on the condition variable. This is why the cond_wait function requires a mutex
// correct usage:
// thread 1:
while (notDone) {
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable
if (ready) {
pthread_mutex_unlock(&mutex);
doWork();
} else {
pthread_cond_wait(&mutex, &cond1);
}
}
// signalling thread
// thread 2:
prepareToRunThread1();
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_cond_signal(&mutex, &cond1);
pthread_mutex_unlock(&mutex);
The mutex is supposed to be locked when you call pthread_cond_wait; when you call it it atomically both unlocks the mutex and then blocks on the condition. Once the condition is signaled it atomically locks it again and returns.
This allows the implementation of predictable scheduling if desired, in that the thread that would be doing the signalling can wait until the mutex is released to do its processing and then signal the condition.
It appears to be a specific design decision rather than a conceptual need.
Per the pthreads docs the reason that the mutex was not separated is that there is a significant performance improvement by combining them and they expect that because of common race conditions if you don't use a mutex, it's almost always going to be done anyway.
https://linux.die.net/man/3/pthread_cond_wait
Features of Mutexes and Condition Variables
It had been suggested that the mutex acquisition and release be
decoupled from condition wait. This was rejected because it is the
combined nature of the operation that, in fact, facilitates realtime
implementations. Those implementations can atomically move a
high-priority thread between the condition variable and the mutex in a
manner that is transparent to the caller. This can prevent extra
context switches and provide more deterministic acquisition of a mutex
when the waiting thread is signaled. Thus, fairness and priority
issues can be dealt with directly by the scheduling discipline.
Furthermore, the current condition wait operation matches existing
practice.
There are a tons of exegeses about that, yet I want to epitomize it with an example following.
1 void thr_child() {
2 done = 1;
3 pthread_cond_signal(&c);
4 }
5 void thr_parent() {
6 if (done == 0)
7 pthread_cond_wait(&c);
8 }
What's wrong with the code snippet? Just ponder somewhat before going ahead.
The issue is genuinely subtle. If the parent invokes
thr_parent() and then vets the value of done, it will see that it is 0 and
thus try to go to sleep. But just before it calls wait to go to sleep, the parent
is interrupted between lines of 6-7, and the child runs. The child changes the state variable
done to 1 and signals, but no thread is waiting and thus no thread is
woken. When the parent runs again, it sleeps forever, which is really egregious.
What if they are carried out while acquired locks individually?
I made an exercice in class if you want a real example of condition variable :
#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
#include "unistd.h"
int compteur = 0;
pthread_cond_t varCond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex_compteur;
void attenteSeuil(arg)
{
pthread_mutex_lock(&mutex_compteur);
while(compteur < 10)
{
printf("Compteur : %d<10 so i am waiting...\n", compteur);
pthread_cond_wait(&varCond, &mutex_compteur);
}
printf("I waited nicely and now the compteur = %d\n", compteur);
pthread_mutex_unlock(&mutex_compteur);
pthread_exit(NULL);
}
void incrementCompteur(arg)
{
while(1)
{
pthread_mutex_lock(&mutex_compteur);
if(compteur == 10)
{
printf("Compteur = 10\n");
pthread_cond_signal(&varCond);
pthread_mutex_unlock(&mutex_compteur);
pthread_exit(NULL);
}
else
{
printf("Compteur ++\n");
compteur++;
}
pthread_mutex_unlock(&mutex_compteur);
}
}
int main(int argc, char const *argv[])
{
int i;
pthread_t threads[2];
pthread_mutex_init(&mutex_compteur, NULL);
pthread_create(&threads[0], NULL, incrementCompteur, NULL);
pthread_create(&threads[1], NULL, attenteSeuil, NULL);
pthread_exit(NULL);
}