condition_variable
std::condition_variable is a synchronization primitive used with a std::mutex to block one or more threads until another thread both modifies a shared variable (the condition) and notifies the std::condition_variable.
The thread that intends to modify the shared variable must:
-
Acquire a std::mutex (typically via std::lock_guard).
-
Modify the shared variable while the lock s owned.
-
Call notify_one or notify_all on the std::condition_variable (can be done after releasing the lock).
Even if the shared variable is atomic, it must be modified while owning the mutex to correctly publish the modification to the waiting thread.
Any thread that intends to wait on a std::condition_variable must:
-
Acquire a std::unique_lock<std::mutex> on the mutex used to protect the shared variable.
-
Do one of the following:
-
Acquire a std::unique_lock<std::mutex> on the mutex used to protect the shared variable.
-
Call wait, wait_for, or wait_until on the std::condition_variable (atomically releases the mutex and suspends thread execution until the condition variable is notifiued, a timeout expires, or a spurious wakeup occurs, then atomically acquires the mutex before returning).
-
Check the condition and resume waiting if not satisfied.
or
- Use the predicated overload of
wait, wait_for, and wait_until, which performs the same three steps.
std::condition_variable works only with std::unique_lock<std::mutex>, which allows for maximal effciency on some platforms. std::condition_variable_any provides a condition variable that works with any BasicLockable object, such as std::shad_lock.
Condition variables permit concurrent invocation of the wait, wait_for, wait_until, notify_one and notify_all member functions.
The class std::condition_variable is a StandardLayoutType. It is not CopyConstructible, MoveConstructible, CopyAssignable, or MoveAssignable.
Example
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread() {
std::unique_lock lk(m);
cv.wait(lk, []{ return ready; });
std::cout << "Worker thread is processing data \n";
data += " after processing";
processed = true;
std::cout << "Worker thread signals data processing completed\n";
lk.unlock();
cv.notify_one();
}
int main() {
std::thread worker(worker_thread);
data = "Example data";
{
std::lock_guard lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
{
std::unique_lock lk(m);
cv.wait(lk, []{ return processed; });
}
std::cout << "Back in main(), data = " << data << "\n";
worker.join();
return 0;
}
Reference
- cppreference.com