using a mutex as a condition variable - c++

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.

Related

std::condition_variable memory writes visibility

Does std::condition_variable::notify_one() or std::condition_variable::notify_all() guarantee that non-atomic memory writes in the current thread prior to the call will be visible in notified threads?
Other threads do:
{
std::unique_lock lock(mutex);
cv.wait(lock, []() { return values[threadIndex] != 0; });
// May a thread here see a zero value and therefore start to wait again?
}
Main thread does:
fillData(values); // All values are zero and all threads wait() before calling this.
cv.notify_all(); // Do need some memory fence or lock before this
// to ensure that new non-zero values will be visible
// in other threads immediately after waking up?
Doesn't notify_all() store some atomic value therefore enforcing memory ordering? I did not clarified it.
UPD: according to Superlokkus' answer and an answer here: we have to acquire a lock to ensure memory writes visibility in other threads (memory propagation), otherwise threads in my case may read zero values.
Also I missed this quote here about condition_variable, which specifically answers my question. Even an atomic variable has to be modified under a lock in a case when the modification must become visible immediately.
Even if the shared variable is atomic, it must be modified under the
mutex in order to correctly publish the modification to the waiting
thread.
I guess you are mixing up memory ordering of so called atomic values and the mechanisms of classic lock based synchronization.
When you have a datum which is shared between threads, lets say an int for example, one thread can not simply read it while the other thread might be write to it meanwhile. Otherwise we would have a data race.
To get around this for long time we used classic lock based synchronization:
The threads share at least a mutex and the int. To read or to write any thread has to hold the lock first, meaning they wait on the mutex. Mutexes are build so that they are fine that this can happen concurrently. If a thread wins gettting the mutex it can change or read the int and then should unlock it, so others can read/write too. Using a conditional variable like you used is just to make the pattern "readers wait for a change of a value by a writer" more efficient, they get woken up by the cv instead of periodically waiting on the lock, reading, and unlocking, which would be called busy waiting.
So because you hold the lock in any after waiting on the mutex or in you case, correctly (mutex is still needed) waiting on the conditional variable, you can change the int. And readers will read the new value after the writer was able to wrote it, never the old. UPDATE: However one thing if have to add, which might also be the cause of confusion: Conditional variables are subject for so called spurious wakeups. Meaning even though you write did not have notified any thread, a read thread might still wake up, with the mutex locked. So you have to check if you writer actually waked you up, which is usually done by the writer by changing another datum just to notify this, or if its suitable by using the same datum you already wanted to share. The lambda parameter overload of std::condition_variable::wait was just made to make the checking and going back to sleep code looking a bit prettier. Based on your question now I don't know if you want to use you values for this job.
However at snippet for the "main" thread is incorrect or incomplete:
You are not synchronizing on the mutex in order to change values.
You have to hold the lock for that, but notifying can be done without the lock.
std::unique_lock lock(mutex);
fillData(values);
lock.unlock();
cv.notify_all();
But these mutex based patters have some drawbacks and are slow, only one thread at a time can do something. This is were so called atomics, like std::atomic<int> came into play. They can be written and read at the same time without an mutex by multiple threads concurrently. Memory ordering is only a thing to consider there and an optimization for cases where you uses several of them in a meaningful way or you don't need the "after the write, I never see the old value" guarantee. However with it's default memory ordering memory_order_seq_cst you would also be fine.

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.

C++ Mutexes- Check if another thread is waiting

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.

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

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

signal and unlock order

void WorkHandler::addWork(Work* w){
printf("WorkHandler::insertWork Thread, insertWork locking \n");
lock();
printf("WorkHandler::insertWork Locked, and inserting into queue \n");
m_workQueue.push(w);
signal();
unLock();
}
I followed a tutorial and I got this. I was wondering if it is ok to change the order of singal() and unLock() like this
void WorkHandler::addWork(Work* w){
printf("WorkHandler::insertWork Thread, insertWork locking \n");
lock();
printf("WorkHandler::insertWork Locked, and inserting into queue \n");
m_workQueue.push(w);
unLock();
signal();
}
If I can't do this, could you please give me details why I am not allowed to do this?
Thanks in advance.
First, there is no correctness issue here. Either order will work. Recall that whenever you use condition variables, you must loop on a predicate while waiting:
pthread_mutex_lock(mutex);
while (!predicate)
pthread_cond_wait(cvar);
pthread_mutex_unlock(mutex);
By signalling after the unlock, you don't introduce any correctness issues; the thread is still guaranteed to wake up, and the worst case is another wakeup comes first - at which point it sees the predicate becomes true and proceeds.
However, there are two possible performance issues that can come up.
"Hurry up and wait". Basically, if you signal while the lock is held, the other thread still needs to wait until the mutex is available. Many pthreads implementations will, instead of waking up the other thread, simply move it to the wait queue of the mutex, saving an unnecessary wakeup->wait cycle. In some cases, however this is unimplemented or unavailable, leading to a potential spurious context switch or IPI.
Spurious wakeups. If you signal after the unlock, it's possible for another thread to issue another wakeup. Consider the following scenario:
Thread A starts waiting for items to be added to a threadsafe queue.
Thread B inserts an item on the queue. After unlocking the queue, but before it issues the signal, a context switch occurs.
Thread C inserts an item on the queue, and issues the cvar signal.
Thread A wakes up, and processes both items. It then goes back to waiting on the queue.
Thread B resumes, and signals the cvar.
Thread A wakes up, then immediately goes back to sleep, because the queue is empty.
As you can see, this can introduce a spurious wakeup, which might waste some CPU time.
Personally, I don't think it's worth worrying too much about it either way. You don't often know offhand whether your implementation supports moving waiters from the condition variable to the mutex wait queue, which is the only real criterion you could use to decide which to use.
My gut feeling would be that, if I had to choose, signalling after the unlock is marginally less likely to introduce an inefficiency, as the inefficiency requires a three-thread race, rather than a two-thread race for the "hurry up and wait" condition. However, this is not really worth worrying about, unless benchmarks show too much context switch overhead or something.
This article is really worth reading towards your question:
Signal with mutexed or not?
Assuming you use same mutex with conditional variable to make condition change to be atomic. There are two cases and you should know their behavior:
wait on signal (conditional var) while holding the mutex. The result is to let thread join the conditional var's queue and then go to sleep.
signaled but without mutex. For this case, the thread won't sleep but block on it. (A mistake I made on this is that I thought it will sleep too. In this case, if producer signals and context switch happens right before it releases mutex, then all threads will wake up and know they can't lock the mutex, go to sleep forever. This is wrong because they won't sleep but wait and block).
Pthreads are implemented with wait-morphing, that is, instead of waking up threads upon signaling, it just transfer threads on conditional variable to the attached mutex queue. So signal while locking is more preferable without too much performance impact.
For signaling before unlocking mutex, it may causes spurious wake-up. If your code is not well designed to handle predicate changes made by spurious wake-up, you should choose signal while holding the lock.
The answer to your question is "Yes". In fact, it's slightly preferable (as you've probably guessed) as it avoids the 'hurry up and wait' issue of waking up a thread to test a condition only to have it immediately block on the mutex it needs to acquire before testing the condition.
This answer is predicated on the guess that these things hold true:
lock is a thin wrapper for pthread_mutex_lock.
unLock is a thin wrapper for pthread_mutex_unlock.
signal is a thing wrapper for pthread_cond_signal.
The mutex your locking and unlocking is the one that your giving to pthread_cond_wait.