Thanks for this, from this base I improved the code by adding infinite loops and scoped locks so that they communicate indefinitely, which is more a common used case
I think there is a bug here. if(!notified) should be while(!notified) in case of spurious wakeups. As it said in the cppreference documentation for wait, the predicate version of wait is equivalent to: while (!stop_waiting()) { wait(lock); } Have I misunderstood something ? It's quite likely I have, as I haven't written multithreaded C++ for a couple of years and I'm watching these videos to refresh my memory.
Agreed, I think this is a bug in the video and my Code. This I think has been updated on cppreference as well (it's possible my interpretation was a bug as well)
After notify_one, the reporter thread tries to re-aquire the lock, but it is already locked by the worker thread (until the lock goes out of scope). If the lock would not go out of scope in the worker thread, a lock.unlock() would be needed before (or after) notify_one(), in order to allow the reporter thread to re-aquire the lock after wait, otherwise the reporter thread would remain blocked.
Hi Mike , this example similar to many examples out there , i think the idea of conditional variable is where the thread not finished , and have while (true) or while (m_running) than you need to use the unlock and lock of the unique lock, so this example need to be advanced little more.
I suppose an example using say a producer/consumer where the producers and consumers have infinite loops waiting for items to be placed on a queue (or spaces available on the queue for a producer) would be another good example to use conditional variables :)
@@vb9950 Semaphores are one of the lowest level synchronization primitives. They can be used as barriers, used like mutexes, etc., so many use cases for them.
Thanks for the tutorial video, Mike. Feedback on the example program: I ran into the issue of "lost wakeup" with condition variables while trying out this.
Wouldn't the code be simpler if you eliminate the `notified` boolean? Can't you just always let the worker signal to the reporter thread, instead of filtering it with the boolean?
Hi MIke, this seems to work without the notified boolean variable. Although does that mean the reporter thread keeps on polling our conditional variable?
Hello Mike! Do you think you could do a video on the concept of Semaphores? It was recently added in C++20, see std::counting_semaphore, std::binary_semaphore, but I'm having a hard time understanding the use cases, and what exactly is the difference between a Semaphore and a conditional variable (when should you use one and not the other). Thanks!
Yes, will add those to the series. Trying to wrap up a few other video series, but will otherwise revisit the concurrency -- I've started drafting some notes already, not sure on exact ETA yet for new lessons, likely around Fall
Thanks Mike for this great series! I have a question: If a thread that is blocked on a std::condition_variable is notified, but the lock on the associated mutex has not been released and let’s say the lock is going to be released 10 seconds later, would the waiting thread wait for the lock to be released or the situation would be undefined?
Should remain blocked on the lock if I understand the question correctly: en.cppreference.com/w/cpp/thread/condition_variable condition_variable needs a unique_lock
Just as when I got 2 threads hung, your video shows up 😀. Can you think of a case where 2 mutexes might be needed in your example. I ask that, as my worker thread calls lock via unique lock, as the reporter thread starts and takes the lock, it seems lock is called on a locked mutex, which is undefined behavior. The worker lock call followed by cv wait, so if predicate is false the mutex will be unlocked for reporter to grab it. So could the case where worker condition is met so lock is held, meantime report tries to grab is resulting in UB. I am reluctant to use 2 mutex solutions, it makes no sense, here mutex with cv is used to protect shared data, can done with 1 mutex. But how to prevent locking a locked mutex. Thanks Mike
Two mutexes tend to show up in patterns like producer/consumer or readers/writers problems. If you have some intermediate data structure where data is being stored you might want to use some condition variable to flag when data is ready for instance.
Thanks for this, from this base I improved the code by adding infinite loops and scoped locks so that they communicate indefinitely, which is more a common used case
Cheers!
I think there is a bug here. if(!notified) should be while(!notified) in case of spurious wakeups.
As it said in the cppreference documentation for wait, the predicate version of wait is equivalent to:
while (!stop_waiting())
{
wait(lock);
}
Have I misunderstood something ? It's quite likely I have, as I haven't written multithreaded C++ for a couple of years and I'm watching these videos to refresh my memory.
Agreed, I think this is a bug in the video and my Code. This I think has been updated on cppreference as well (it's possible my interpretation was a bug as well)
After notify_one, the reporter thread tries to re-aquire the lock, but it is already locked by the worker thread (until the lock goes out of scope). If the lock would not go out of scope in the worker thread, a lock.unlock() would be needed before (or after) notify_one(), in order to allow the reporter thread to re-aquire the lock after wait, otherwise the reporter thread would remain blocked.
Hi Mike! The series is great. My only request would be to create a video on std::promise.
Cheers! Check out this video on futures: ruclips.net/video/4twJD5ezkag/видео.html that may be helpful!
Hi Mike , this example similar to many examples out there , i think the idea of conditional variable is where the thread not finished , and have while (true) or while (m_running) than you need to use the unlock and lock of the unique lock, so this example need to be advanced little more.
I suppose an example using say a producer/consumer where the producers and consumers have infinite loops waiting for items to be placed on a queue (or spaces available on the queue for a producer) would be another good example to use conditional variables :)
Thank you this video helped me understand
Cheers!
thanks for making those videos!
You are most welcome! A few more trickling into this series in the next few weeks :)
It's very good series, just wondering why didn't you go through semaphores but only mutexes.
Cheers! Just need more time to plan and record :)
@@MikeShah wow, never expected you to reply to all the comments. Are semaphores necessary, are there any real-time use cases for it?
@@vb9950 Semaphores are one of the lowest level synchronization primitives. They can be used as barriers, used like mutexes, etc., so many use cases for them.
I enjoyed this video, thank you for making it.
You are most welcome!
the notified variable seems useless in this code
It seems like a slight optimization that eliminates the need to wait if the second thread has already finished.
Thanks for the tutorial video, Mike.
Feedback on the example program: I ran into the issue of "lost wakeup" with condition variables while trying out this.
Wouldn't the code be simpler if you eliminate the `notified` boolean? Can't you just always let the worker signal to the reporter thread, instead of filtering it with the boolean?
We do need some variable to store state for condidtional variables, just one of the pieces needed.
Hi MIke, this seems to work without the notified boolean variable. Although does that mean the reporter thread keeps on polling our conditional variable?
Yes, I think some folks have noted that below.
Hello Mike! Do you think you could do a video on the concept of Semaphores? It was recently added in C++20, see std::counting_semaphore, std::binary_semaphore, but I'm having a hard time understanding the use cases, and what exactly is the difference between a Semaphore and a conditional variable (when should you use one and not the other). Thanks!
Yes, will add those to the series. Trying to wrap up a few other video series, but will otherwise revisit the concurrency -- I've started drafting some notes already, not sure on exact ETA yet for new lessons, likely around Fall
Thanks Mike for this great series!
I have a question:
If a thread that is blocked on a std::condition_variable is notified, but the lock on the associated mutex has not been released and let’s say the lock is going to be released 10 seconds later, would the waiting thread wait for the lock to be released or the situation would be undefined?
Should remain blocked on the lock if I understand the question correctly: en.cppreference.com/w/cpp/thread/condition_variable condition_variable needs a unique_lock
@@MikeShah Thank you.
Just as when I got 2 threads hung, your video shows up 😀. Can you think of a case where 2 mutexes might be needed in your example. I ask that, as my worker thread calls lock via unique lock, as the reporter thread starts and takes the lock, it seems lock is called on a locked mutex, which is undefined behavior. The worker lock call followed by cv wait, so if predicate is false the mutex will be unlocked for reporter to grab it. So could the case where worker condition is met so lock is held, meantime report tries to grab is resulting in UB. I am reluctant to use 2 mutex solutions, it makes no sense, here mutex with cv is used to protect shared data, can done with 1 mutex. But how to prevent locking a locked mutex. Thanks Mike
Two mutexes tend to show up in patterns like producer/consumer or readers/writers problems. If you have some intermediate data structure where data is being stored you might want to use some condition variable to flag when data is ready for instance.
What happens if the thread_worker finishes without notify_one?
shouldn't the `result` and `notified` variables be marked as volatile?
I'll need to think about that. To be honest, volatile is difficult to use correctly, but for 'signaling' type of applications it is likely useful.
result = 42... (unintentional I guess haha)