std::condition_variable is a class in c++11, it will be used by thread to wake up other(one or more) waiting thread. In other word, one or multiple threads are waiting for a specific condition, when condition is satisfy then a thread can wake up other (one or more) waiting thread.
Main API of std::condition_variable class (assume std::condition_variable obj;) :
- obj.notify_one(); //wake up only one thread
- obj.notify_all(); //wake up all waiting threads
- 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
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.
Source code with example:
/* Program: Condition Variable Author: Alpha Master Date: 6 Feb 2021 */ //Header File #include<iostream> #include<thread> #include<chrono> #include<mutex> #include<condition_variable> //Global Variable bool dataReady{false}; std::mutex gMtx; std::condition_variable gConVar; int data{0}; //Reader Thread void ReadThread() { auto i{0}; while(i<5) { std::cout<<"!!!Waiting, Data is NOT ready"<<std::endl; { std::unique_lock<std::mutex> ul(gMtx); //Using lambdas, checking flag to avoid suspicious wakeup call //wait internally unlock the mutex so we are using unique pointer gConVar.wait(ul, []{return dataReady;}); std::cout<<"Got the data:"<<data<<std::endl; dataReady = false; } ++i; } } //Writer Thread void WriteThread() { auto i{0}; while(i<5) { //Wait till, data is read by reader while(dataReady) { std::this_thread::sleep_for(std::chrono::seconds(1)); } //Now, Writer will write { std::lock_guard<std::mutex> lg(gMtx); ++data; dataReady = true; //purposefully waiting to verify the result std::this_thread::sleep_for(std::chrono::seconds(1)); } gConVar.notify_one(); ++i; } } int main() { std::cout<<"Conditon variable Functionality"<<std::endl; //Thread 1 and its joinable std::thread t1(ReadThread); //Thread 2 and its also joinable std::thread t2(WriteThread); //std::cout<<"Main thread is Waiting for Child thread"<<std::endl; t1.join(); t2.join(); return 0; };
Output:
Conditon variable Functionality !!!Waiting, Data is NOT ready Got the data:1 !!!Waiting, Data is NOT ready Got the data:2 !!!Waiting, Data is NOT ready Got the data:3 !!!Waiting, Data is NOT ready Got the data:4 !!!Waiting, Data is NOT ready Got the data:5