conditional variable c++
It is a class in c++11 and we need to add header file named as “#include<condition_variable>”.
Problem Statement:
There are two person, one is sweet-maker and other is customer, customer ordered some sweet and he is keep on asking sweet-maker that “Is my sweet ready ?”. His repeating behaviour is annoying to sweet-maker and it creates below problems:
- Customer is wasting his energy because he is going and asking and coming back.
- He is disturbing sweet-maker, his behaviour can delay the outcome.
Solution:
Sweet-maker tells Customer that please don’t come here again and again, just wait outside, when our ordered will be ready then I will signal you. There are two operations:
- wait (customer has to wait and no need to waste his energy and he can go for sleep)
- signal (sweet-maker will signal and can awake customer)
Conclusion: With above solution, customer saves his energy and he will get his sweet early.
Technical Detail:
There are two party, one that will signal (notify) and other is waiting. It will be used by any thread to wake up other(one or more) waiting thread by signalling them.
Main API of std::condition_variable class (assume std::condition_variable obj;) :
Signal API
- obj.notify_one(); //wake up only one thread
- obj.notify_all(); //wake up all waiting threads
Wait API
- obj.wait(ul); //ul is unique pointer, thread waits for notification
- obj.wait_for(ul, duration); //ul is unique pointer, thread waits for notification for duration
- obj.wait_until(ul, time_point); //ul is unique pointer, thread waits for notification until time-point
- obj.wait(ul, []{condition;}); ////ul is unique pointer, thread waits for notification + extra condition
Note:
- wait() API internally unlock the mutex before going to sleep that why we will be using unique lock instead of lock guard.
- wait() API internally lock the mutex after receiving notification from other thread that why we will be using unique lock instead of lock guard.
- Using lambdas, checking flag to avoid suspicious wake up call.
Example: There are two thread(Reader and Writer), Reader is waiting for Writer thread, so using condition variable Writer thread(after completion of writing) can wake up Reader thread and vice-versa.
Source code with example:
/* Program: Author: Alpha Master Date: 25 Aug 2022 */ //Header File #include<iostream> #include<thread> #include<mutex> #include<condition_variable> std::mutex gMtx; std::condition_variable gCv; int gValue = 0; bool gReaderReady = true; bool gWriterReady = false; void reader() { while(true) { std::unique_lock<std::mutex>ul(gMtx); gCv.wait(ul, []{return gReaderReady;}); ++gValue; std::cout<<"Reader:"<<gValue<<std::endl; gReaderReady = false; gWriterReady = true; std::this_thread::sleep_for(std::chrono::seconds(1)); ul.unlock(); gCv.notify_one(); } } void writer() { while(true) { std::unique_lock<std::mutex>ul(gMtx); gCv.wait(ul, []{return gWriterReady;}); std::cout<<"Writer:"<<gValue<<std::endl; gWriterReady = false; gReaderReady = true; std::this_thread::sleep_for(std::chrono::seconds(1)); ul.unlock(); gCv.notify_one(); } } int main() { std::cout<<"Reader and writer"<<std::endl; std::thread T1(reader); std::thread T2(writer); T1.join(); T2.join(); return 0; }
Output:
Reader and writer Reader:1 Writer:1 Reader:2 Writer:2 Reader:3 Writer:3 Reader:4 Writer:4 Reader:5 Writer:5 Reader:6 Writer:6 Reader:7 Writer:7 Reader:8 Writer:8 Reader:9 Writer:9 Reader:10 Writer:10