Interruptible thread example in 《C++ Concurrency In Action》 - c++

《C++ Concurrency In Action》 implements an interruptible thread in Chapter 9.2 Interrupting thread. Listing 9.10 is below:
void interruptible_wait(std::condition_variable& cv,
std::unique_lock<std::mutex>& lk)
{
interruption_point();
this_thread_interrupt_flag.set_condition_variable(cv);
cv.wait(lk);
this_thread_interrupt_flag.clear_condition_variable();
interruption_point();
}
According to the book, this function introduces the problem below:
If the thread is interrupted after the initial call to interruption_point(), but before the call to wait(), then it doesn’t matter whether the condition variable has been associated with the interrupt flag, because the thread isn’t waiting and so can’t be woken by a notify on the condition variable. You need to ensure that the thread can’t be notified between the last check for interruption and the call to wait().
The first question is why we need to ensure that? 'Cause this function seems to run correctly even the thread is interrupted after the initial call to interruption_point() and before the call to wait(). Could anyone tell me how this function will go south? Is it because cv.wait(lk) will never be notified under this situation?
The second question is how Listing 9.11 solve this problem the book mentions just by replacing cv.wait() by cv.wait_for():
void interruptible_wait(std::condition_variable& cv,
std::unique_lock<std::mutex>& lk)
{
interruption_point();
this_thread_interrupt_flag.set_condition_variable(cv);
interrupt_flag::clear_cv_on_destruct guard;
interruption_point();
cv.wait_for(lk,std::chrono::milliseconds(1));
interruption_point();
}

If the other thread calls notify() before this thread gets to wait(), this thread won't receive that notification, and will wait forever for another one.
wait_for doesn't wait forever.

Related

Understanding condition_variable::wait for blocking a thread

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.

std::condition_variable wait() and notify_one() synchronization

Preface: I've seen similar questions here, but not one of them seems to answer my question.
Is there a reliable way to make sure that wait() method in consumer thread is called before the first notify_one() call from the producer thread?
Even with unique_lock in the consumer thread, there is a possibility that the producer thread will run first, lock the mutex and call notify() before the consumer calls wait(), therefore, my app will be missing first notify() call.
EDIT: Thanks for all your answers, they did help me. My problem was with first wait-notify() within this consumer loop:
while (!timeToQuit) {
gdcv.wait(gdcondlock);
gdlock.lock();
//spurious wakeup
if (gdQueue.empty()) {
gdlock.unlock();
continue;
}
//some work here
gdlock.unlock();
}
I guess I'll have to write extra code for the first loop iteration.
EDIT2: This loop and second lock(unique_lock btw) are there because there are multiple producers and consumers accessing queue.
EDIT3: The correct way for waiting on this particular thread with the help of boost::lockfree::queue, in case anyone has similar problem:
nfq_data* data;
while (!timeToQuit) {
gdcv.wait(gdlock,[&]{return !gdQueue.empty() || timeToQuit;});
gdQueue.pop(data);
gdlock.unlock();
}
Even with unique_lock in consumer thread there is a possibility that producer thread will run first, lock the mutex and call noify() before consumer calls wait(), therefore, my app will be missing first nofity() call.
Either the consumer has something to wait for, or it doesn't. If it has something to wait for, there is no problem. If it doesn't have anything to wait for, don't call wait. It really is that simple.
Call wait if, and only if, you want to wait.
Condition variables exist to solve the problem of how you can release a lock and wait without taking the risk that you will wait for something that has already happened. They solve it by providing a function that atomically releases the lock and waits. They cannot miss a wakeup because they hold the lock when they decide to sleep.
It sounds like you are trying to (mis)use condition_variable to implement a "barrier".
A condition variable allows you to wait for some condition to become true, tested via some predicate, e.g. "there is work available", and you should always test the predicate before waiting, which ensures you don't "miss" the event and wait when you should be working.
Using a condition variable purely to wait, without an associated predicate, does not work well. That's not how they are designed to be used.
If you are trying to make all threads wait at a particular point in the code and only proceed when they have all arrived then you are using a slightly different concept, known as a barrier.
The C++ Concurrency TS defines barriers (and the slightly simpler concept of "latches") for the C++ Standard Library, see the draft N4538.
You can define a barrier yourself by defining a class with a counter, which uses a condition_variable internally. The condition it needs to wait on is "all N threads have incremented the counter". Then you can make the producer and all consumers wait at the barrier, and they will all block until the last thread reaches the barrier. Even if the producer reaches the barrier and starts waiting first, you are guaranteed that the consumers will also stop and wait at the barrier, until all threads reach it, then they will all proceed.
No, it's up to you to take care of threads synchronization.
If you don't want to miss a notify call even if it happens before the the consumer starts waiting, you must control this eventuality, recording somewhere that the producer is done, and then not call the wait() function at all.
For example, you can implement a sort of event class, that wait on the condition variable only if the event has not happened yet:
#include <mutex>
#include <condition_variable>
class Event
{
public:
Event();
void set_event();
void reset_event();
void wait_event();
private:
std::mutex mtx;
std::condition_variable cv;
bool is_set;
};
Event::Event()
: is_set{false}
{}
void Event::set_event()
{
std::lock_guard<std::mutex> lck{mtx};
is_set = true;
cv.notify_all();
}
void Event::reset_event()
{
std::lock_guard<std::mutex> lck{mtx};
is_set = false;
}
void Event::wait_event()
{
std::unique_lock<std::mutex> lck{mtx};
if( is_set )
return;
cv.wait(lck, [this]{ return is_set;} );
}
Even with unique_lock in consumer thread there is a possibility that producer thread will run first, lock the mutex and call noify() before consumer calls wait(), therefore, my app will be missing first nofity() call
If the producer has already run, then the consumer doesn't have to wait and therefore shouldn't call wait. If the consumer only waits when it needs to - and the condition is snychronized - then it cannot miss a notify that it needs to notice.

Why do both the notify and wait function of a std::condition_variable need a locked 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.

thread_cancel and blocking function as cond_wait

I have my main process send pthread_cancel to another thread which is waiting for a condition to happen with cond_wait(&condition). On the pthread_cancel they are saying : Deferred cancel ability means that cancellation will be delayed until the thread next calls a function that is a cancellation point. But often those function are blocking function. Then my question is the thread cancelled only after that thread has been unblock (in my example by a broadcast or a signal) or it would see that i am currently blocking on a cancellation point and then cancelled my thread ?
I'm not familiar with cond_wait, but I presume it's from another library than the typically used pthread_cond_wait?
But yes, if a thread is blocked in a pthread_cond_wait and then cancelled, the thread will be woken up, reacquire it's mutex, and then be canceled.
There are thus two important points here to keep in mind when canceling threads that are blocked on a condition:
Make sure that the mutex is unlocked (or will be unlocked at some point in the future), before calling pthread_cancel. For instance, if thread A is waiting on a condition, and thread B locks the condition mutex, calls pthread_cancel and then pthread_join before unlocking the condition mutex, you'll deadlock.
Install a cleanup handler (see pthread_cleanup_push) to unlock your condition mutex before calling pthread_cond_wait - otherwise you'll cancel your thread and leave the mutex locked.
However, note also that the pthread condition variable implementation has had/has some bugs - so be sure to use an up-to-date glibc.
You might want to use pthread_cond_wait instead of cond_wait.
If you use pthread_cond_wait and based on this from man pthread_cond_wait(3)
A condition wait (whether timed or not) is a cancellation point. When the cancelability enable state of a thread is set to PTHREAD_CANCEL_DEFERRED, a side effect of acting upon a cancellation request while in a condition wait is that the mutex is (in effect) re-acquired before calling the first cancellation cleanup handler. The effect is as if the thread were unblocked, allowed to execute up to the point of returning from the call to pthread_cond_timedwait() or pthread_cond_wait(), but at that point notices the cancellation request and instead of returning to the caller of pthread_cond_timedwait() or pthread_cond_wait(), starts the thread cancellation activities, which includes calling cancellation cleanup handlers.
It looks like the thread will cancel on pthread_cond_wait even if it's currently blocked
Or you could set the cancellation type with pthread_setcanceltype to ASYNCHRONOUS. see comment below
But like most of the time, the best way to know for sure would be to try it with a test code.

std::condition_variable::notify_one() called several times without context switching

How many waiting threads will wake up in this example:
1st thread:
void wakeUp2Threads()
{
std::unique_lock<std::mutex> lock(condvar_mutex);
condvar.notify_one();
condvar.notify_one();
}
2nd thread:
{
std::unique_lock<std::mutex> lock(condvar_mutex);
condvar.wait(lock); <- 2nd thread has entered here before 1st thread entered wakeUp2Threads.
}
3rd thread (the same as 2nd):
{
std::unique_lock<std::mutex> lock(condvar_mutex);
condvar.wait(lock); <- 3rd thread has entered here before 1st thread entered wakeUp2Threads.
}
Is there any guarantee that in this example both notifications will be delivered to different threads, not the same thread several times?
I.e what does notify_one() mean:
1) notify one thread, no matter has it been already notified (but has not been woken up yet), or not. (* see note)
or
2) notify one thread, but only this one, which has not been notified yet.
(*) Pay attention! I'm not talking here about scenario "waiting thread had already been notified somewhere in the past, woken up, done some stuff and entered condvar.wait() again" - of course, in this case several notify_one() routines can wake up the same thread over and over again.
I'm talking about another case:
notify_one() has notified waiting thread about wake-up, but BEFORE this waiting thread has received time slot form the kernel scheduler and continued execution - another notify_one() has been called again. Is it possible this second notification will be delivered to the same thread again, while it hasn't been woken up from first notification yet?
The notify_one call atomically unblocks one thread. That means that when called a second time it can't unblock the same thread as it's no longer blocked.
This is specified in the standard at section 30.5/3 and 30.5.1/7.