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.
Related
While implementing a thread pool pattern in C++ based on this, I came across a few questions.
Let's assume minimal code sample:
std::mutex thread_mutex;
std::condition_variable thread_condition;
void thread_func() {
std::unique_lock<std::mutex> lock(thread_mutex);
thread_condition.wait(lock);
lock.unlock();
}
std::thread t1 = std::thread(thread_func);
Regarding cppreference.com about conditon_variable::wait(), wait() causes the current thread to block. What is locking the mutex then for when I only need one thread at all using wait() to get notified when something is to do?
unique_lock will block the thread when the mutex already has been locked by another thread. But this wouldn't be neccesary as long as wait() blocks anyway or what do I miss here?
Adding a few lines at the bottom...
std::thread t2 = std::thread(thread_func);
thread_condition.notify_all()
When unique_lock is blocking the thread, how will notify_all() reach both threads when one of them is locked by unique_lock and the other is blocked by wait()? I understand that blocking wait() will be freed by notify_all() which afterwards leads to unlocking the mutex and that this gives chance to the other thread for locking first the mutex and blocking thread by wait() afterwards. But how is this thread notified than?
Expanding this question by adding a loop in thread_func()...
std::mutex thread_mutex;
std::condition_variable thread_condition;
void thread_func() {
while(true) {
std::unique_lock<std::mutex> lock(thread_mutex);
thread_condition.wait(lock);
lock.unlock();
}
}
std::thread t1 = std::thread(thread_func);
std::thread t2 = std::thread(thread_func);
thread_condition.notify_all()
While reading documentation, I would now expect both threads running endlessly. But they do not return from wait() lock. Why do I have to use a predicate for expected behaviour like this:
bool wakeup = false;
//[...]
thread_condition.wait(lock, [] { return wakeup; });
//[...]
wakeup = !wakeup;
thread_condition.notify_all();
Thanks in advance.
This is really close to being a duplicate, but it's actually that question that answers this one; we also have an answer that more or less answers this question, but the question is distinct. I think that an independent answer is needed, even though it's little more than a (long) definition.
What is a condition variable?
The operational definition is that it's a means for a thread to block until a message arrives from another thread. A mutex alone can't possibly do this: if all other threads are busy with unrelated work, a mutex can't block a thread at all. A semaphore can block a lone thread, but it's tightly bound to the notion of a count, which isn't always appropriate to the nature of the message to receive.
This "channel" can be implemented in several ways. Very low-tech is to use a pipe, but that involves expensive system calls. Windows provides the Event object which is fundamentally a boolean on whose truth a thread may wait. (C++20 provides a similar feature with atomic_flag::wait.)
Condition variables take a different approach: their structural definition is that they are stateless, but have a special connection to a corresponding mutex type. The latter is necessitated by the former: without state, it is impossible to store a message, so arrangements must be made to prevent sending a message during some interval between a thread recognizing the need to wait (by examining some other state: perhaps that the queue from which it wants to pop is empty) and it actually being blocked. Of course, after the thread is blocked it cannot take any action to allow the message to be sent, so the condition variable must do so.
This is implemented by having the thread take a mutex before checking the condition and having wait release that mutex only after the thread can receive the message. (In some implementations, the mutex is also used to protect the workings of the condition variable, but C++ does not do so.) When the message is received, the mutex is re-acquired (which may block the thread again for a time), as is necessary to consult the external state again. wait thus acts like an everted std::unique_lock: the mutex is unlocked during wait and locked again afterwards, with possibly arbitary changes having been made by other threads in the meantime.
Answers
Given this understanding, the individual answers here are trivial:
Locking the mutex allows the waiting thread to safely decide to wait, given that there must be some other thread affecting the state in question.
If the std::unique_lock blocks, some other thread is currently updating the state, which might actually obviate the need for wait.
Any number of threads can be in wait, since each unlocks the mutex when it calls it.
Waiting on a condition variable, er, unconditionally is always wrong: the state you're after might already apply, with no further messages coming.
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.
On my neverending quest to understand std::contion_variables I've run into the following. On this page it says the following:
void print_id (int id) {
std::unique_lock<std::mutex> lck(mtx);
while (!ready) cv.wait(lck);
// ...
std::cout << "thread " << id << '\n';
}
And after that it says this:
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
}
Now as I understand it, both of these functions will halt on the std::unqique_lock line. Until a unique lock is acquired. That is, no other thread has a lock.
So say the print_id function is executed first. The unique lock will be aquired and the function will halt on the wait line.
If the go function is then executed (on a separate thread), the code there will halt on the unique lock line. Since the mutex is locked by the print_id function already.
Obviously this wouldn't work if the code was like that. But I really don't see what I'm not getting here. So please enlighten me.
What you're missing is that wait unlocks the mutex and then waits for the signal on cv.
It locks the mutex again before returning.
You could have found this out by clicking on wait on the page where you found the example:
At the moment of blocking the thread, the function automatically calls lck.unlock(), allowing other locked threads to continue.
Once notified (explicitly, by some other thread), the function unblocks and calls lck.lock(), leaving lck in the same state as when the function was called.
There's one point you've missed—calling wait() unlocks the mutex. The thread atomically (releases the mutex + goes to sleep). Then, when woken by the signal, it tries to re-acquire the mutex (possibly blocking); once it acquires it, it can proceed.
Notice that it's not necessary to have the mutex locked for calling notify_*, only for wait*
To answer the question as posed, which seems necessary regarding claims that you should not acquire a lock on notification for performance reasons (isn't correctness more important than performance?): The necessity to lock on "wait" and the recommendation to always lock around "notify" is to protect the user from himself and his program from data and logical races. Without the lock in "go", the program you posted would immediately have a data race on "ready". However, even if ready were itself synchronized (e.g. atomic) you would have a logical race with a missed notification, because without the lock in "go" it is possible for the notify to occur just after the check for "ready" and just before the actual wait, and the waiting thread may then remain blocked indefinitely. The synchronization on the atomic variable itself is not enough to prevent this. This is why helgrind will warn when a notification is done without holding the lock. There are some fringe cases where the mutex lock is really not required around the notify. In all of these cases, there needs to be a bidirectional synchronization beforehand so that the producing thread can know for sure that the other thread is already waiting. IMO these cases are for experts only. Actually, I have seen an expert, giving a talk about multi-threading, getting this wrong — he thought an atomic counter would suffice. That said, the lock around the wait is always necessary for correctness (or, at least, an operation that is atomic with the wait), and this is why the standard library enforces it and atomically unlocks the mutex on entering the wait.
POSIX condition variables are, unlike Windows events, not "idiot-proof" because they are stateless (apart from being aware of waiting threads). The recommendation to use a lock on the notify is there to protect you from the worst and most common screwups. You can build a Windows-like stateful event using a mutex + condition var + bool variable if you like, of course.
Is it possible for a thread that already has a lock on a mutex to check whether another thread is already waiting, without releasing the mutex? For example, say a thread has 3 tasks to run on a block of data, but another thread may have a short task to run on the data as well. Ideally, I'd have the first thread check whether another thread is waiting between each of the three tasks and allow the other thread to execute its task before resuming the other two tasks. Does Boost have a type of mutex that supports this functionality (assuming the C++11 mutex or lock types don't support this), or can this be done with conditional variables?
You cannot check whether other threads are waiting on a mutex.
If you want to give other threads their chance to run, just release the mutex. No need to know if someone is waiting. Then re-acquire as necessary.
Conditional variables are events. Use them if you want to wait until something happens. To check whether something has happened you need a regular (mutex-protected or atomic) variable.
you can not check if other threads are waiting on a mutex.
if you do need such functionality, you need to implement your own.
a mutex with use_count will suffice your need.
class my_mutex{
public:
my_mutex() {count=0;}
void lock() {count++; mtx.lock();}
void unlock() {count--; mtx.unlock();}
size_t get_waiting_threads() {return count>1?count-1:0;}
private:
atomic_ulong count;
mutex mtx;
};
if you need to finish task 1 and 2 before task 3 is executed, you should use conditional_variable instead of mutex.
If two threads are waiting on a lock, the thread that started waiting first is not guaranteed to be the thread that gets it first when it becomes available. So if you're a tight-looping thread who does something like
while(true):
mutex.lock()
print "got the lock; releasing it"
mutex.unlock()
You might think you're being polite to all the other threads waiting for the lock, but you're not, the system might just give you the lock over and over again without letting any of the other threads jump in, no matter how long they've been waiting.
Condition variables are a reasonable way to solve this problem.
Given the canonical example for condition variables
pthread_mutex_lock(&count_mutex);
pthread_cond_wait(&count_threshold_cv, &count_mutex);
Then I can send a signal from another thread, and this thread will continue.
But I fail to see whats wrong with just trying to lock a mutex, and if the lock is taken then the thread will wait for the mutex lock to be released.
Is the only problem with this approach the constant polling?
Thanks
Let's make this concrete. Your suggested alternative to condition variables is for the "waiter" to do this:
loop:
lock mutex
check predicate
if (predicate is false)
unlock mutex
sleep a bit // (is this what you had in mind?)
goto loop
And for the "signaler" to do this:
lock mutex
make predicate true
unlock mutex
Here, "predicate" might be "the queue is not empty", for instance.
There are two problems with this approach. The first is the one you identified: The constant polling is inefficient. If you imagine hundreds or thousands of threads across the whole system trying to operate this way, it would bring the system to its knees. Or your "sleep a bit" would have to be so long that the sleeps themselves would add up to annoying delays.
The second problem is more subtle. There is no guarantee that when a thread unlocks a mutex and then locks it again, another thread waiting on that mutex will be allowed to run. (This property of a mutex is called "fairness"; a mutex that provides it is said to be "fair". POSIX does not require mutexes to be fair.) No matter how long you sleep in the "waiter", there is no guarantee that the "signaler" will ever get past its lock mutex call.
Condition variables solve both of these problems.
Condition variables signal changes to data structures protected by mutexes. E.g. you may have a queue protected by a mutex, and when it gets empty, you want the consumer to wait on a condition variable until the queue is no longer empty. You want to atomically release the mutex and wait in that situation.