C ++ 11 concurrent programming-condition_variable
The header file mainly contains classes and functions related to condition variables. Related classes includestd::condition_variableAndstd::condition_variable_anyAnd the enumerated type.std::cv_status. Functions are also included.std::notify_all_at_thread_exit()The following describes the above types.
Std: condition_variable class Introduction
std::condition_variableIs a condition variable. For more definitions of condition variables, see Wikipedia.LinuxUsePthreadLibrarypthread_cond_*()Functions provide functions related to conditional variables,WindowsFor more information, seeMSDN.
Whenstd::condition_variableAn objectwaitWhen a function is called, it usesstd::unique_lock(Passstd::mutex) To lock the current thread. The current thread will be blocked until another thread is in the samestd::condition_variableObject callednotificationFunction to wake up the current thread.
std::condition_variableObjects usually usestd::unique_lock To wait, if you need to use anotherlockableType, which can be usedstd::condition_variable_anyClass, which will be discussed later in this articlestd::condition_variable_any.
# Include
// Std: cout # include
// Std: thread # include
// Std: mutex, std: unique_lock # include
// Std: condition_variablestd: mutex CTX; // global mutex lock. std: condition_variable cv; // global condition variable. bool ready = false; // global flag. void do_print_id (int id) {std: unique_lock
Lck (CTX); while (! Ready) // if the flag bit is not true, wait... cv. wait (lck); // The current thread is blocked. When the global flag bit is set to true, // The thread is awakened and the print thread id continues. std: cout <"thread" <id <'\ n';} void go () {std: unique_lock
Lck (CTX); ready = true; // you can specify true as the global flag. cv. notify_all (); // wake up all threads .} int main () {std: thread threads [10]; // spawn 10 threads: for (int I = 0; I <10; ++ I) threads [I] = std: thread (do_print_id, I); std: cout <"10 threads ready to race... \ n "; go (); // go! For (auto & th: threads) th. join (); return 0 ;}
Result:
10 threads ready to race...thread 1thread 0thread 2thread 3thread 4thread 5thread 6thread 7thread 8thread 9
Well, after having a basic understanding of conditional variables, let's take a look.std::condition_variable.
std::condition_variableOnly the default constructor is provided.
std::condition_variable::wait()Introduction:
void wait (unique_lock
& lck);template
void wait (unique_lock
& lck, Predicate pred);
std::condition_variableProvides two typeswait()Function. Current thread callwait()Then it will be blocked (the current thread should get the lock (mutex).lck) Until another thread callsnotify_*The current thread is awakened.
This function is automatically called when the thread is blocked.lck.unlock()Release the lock so that other threads blocked in lock competition can continue to execute. In addition, once the current thread gets a notification (notified, Usually called by another threadnotify_*Wake up the current thread ),wait()The function is also called automatically.lck.lock(), MakinglckStatus andwaitFunctions are the same when called.
In the second case (that is,Predicate), Only whenpredThe condition isfalseTime callwait()Will block the current thread, and only whenpredIstrueWill be removed. The second case is similar to the following code:
while (!pred()) wait(lck);
# Include
// Std: cout # include
// Std: thread, std: this_thread: yield # include
// Std: mutex, std: unique_lock # include
// Std: condition_variablestd: mutex CTX; std: condition_variable cv; int cargo = 0; bool shipment_available () {return cargo! = 0;} // consumer thread. void consume (int n) {for (int I = 0; I <n ;++ I) {std: unique_lock
Lck (CTX); cv. wait (lck, shipment_available); std: cout <cargo <'\ n'; cargo = 0 ;}} int main () {std: thread consumer_thread (consume, 10); // consumer thread. // The main thread is the producer thread, producing 10 items. for (int I = 0; I <10; ++ I) {while (shipment_available () std: this_thread: yield (); std: unique_lock
Lck (CTX); cargo = I + 1; cv. policy_one () ;}consumer_thread.join (); return 0 ;}
12345678910
Std: condition_variable: wait_for ()
template
cv_status wait_for (unique_lock
& lck, const chrono::duration
& rel_time);template
bool wait_for (unique_lock
& lck, const chrono::duration
& rel_time, Predicate pred);
Andstd::condition_variable::wait()Similar,wait_forYou can specify a time period when the current thread receives a notification or the specified time.rel_timeBefore timeout, the thread will be in the blocking status. Once timeout or other threads are notified,wait_forReturn, the remaining processing steps andwait()Similar.
In addition,wait_forThe last parameter of the overloaded version.predIndicateswait_forOnly whenpredThe condition isfalseTime callwait()Will block the current thread, and only whenpredIstrueWill be removed, so it is equivalent to the following code:
return wait_until (lck, chrono::steady_clock::now() + rel_time, std::move(pred));
Please refer to the following example (reference). In the following example, the main thread waitsthThe thread inputs a value and thenthThe value received by the thread from the terminal is printed inthBefore the thread receives the value, the main thread waits until every second times out and prints".":
#include
// std::cout#include
// std::thread#include
// std::chrono::seconds#include
// std::mutex, std::unique_lock#include
// std::condition_variable, std::cv_statusstd::condition_variable cv;int value;void do_read_value(){ std::cin >> value; cv.notify_one();}int main (){ std::cout << "Please, enter an integer (I'll be printing dots): \n"; std::thread th(do_read_value); std::mutex mtx; std::unique_lock
lck(mtx); while (cv.wait_for(lck,std::chrono::seconds(1)) == std::cv_status::timeout) { std::cout << '.'; std::cout.flush(); } std::cout << "You entered: " << value << '\n'; th.join(); return 0;}
Std: condition_variable: wait_until Introduction
template
cv_status wait_until (unique_lock
& lck, const chrono::time_point
& abs_time);template
bool wait_until (unique_lock
& lck, const chrono::time_point
& abs_time, Predicate pred);
Andstd::condition_variable::wait_forSimilar,wait_untilYou can specify a time point when the current thread receives a notification or a specified time point.abs_timeBefore timeout, the thread will be in the blocking status. Once timeout or other threads are notified,wait_untilReturn, the remaining processing steps andwait_until()Similar.
In addition,wait_untilThe last parameter of the overloaded version.predIndicateswait_untilOnly whenpredThe condition isfalseTime callwait()Will block the current thread, and only whenpredIstrueWill be removed, so it is equivalent to the following code:
while (!pred()) if ( wait_until(lck,abs_time) == cv_status::timeout) return pred();return true;
Std: condition_variable: policy_one ()
Wake up a wait (wait) Thread. If no waiting thread exists, the function does not do anything. If multiple waiting threads exist at the same time, it is uncertain to wake up a thread.(unspecified).
See the following example (reference ):
#include
// std::cout#include
// std::thread#include
// std::mutex, std::unique_lock#include
// std::condition_variablestd::mutex mtx;std::condition_variable cv;int cargo = 0; // shared value by producers and consumersvoid consumer(){ std::unique_lock < std::mutex > lck(mtx); while (cargo == 0) cv.wait(lck); std::cout << cargo << '\n'; cargo = 0;}void producer(int id){ std::unique_lock < std::mutex > lck(mtx); cargo = id; cv.notify_one();}int main(){ std::thread consumers[10], producers[10]; // spawn 10 consumers and 10 producers: for (int i = 0; i < 10; ++i) { consumers[i] = std::thread(consumer); producers[i] = std::thread(producer, i + 1); } // join them back: for (int i = 0; i < 10; ++i) { producers[i].join(); consumers[i].join(); } return 0;}
Std: condition_variable: policy_all ()
Wake up all waits(wait)Thread. If there is no waiting thread, this function does not do anything. See the following example:
# Include
// Std: cout # include
// Std: thread # include
// Std: mutex, std: unique_lock # include
// Std: condition_variablestd: mutex CTX; // global mutex lock. std: condition_variable cv; // global condition variable. bool ready = false; // global flag. void do_print_id (int id) {std: unique_lock
Lck (CTX); while (! Ready) // if the flag bit is not true, wait... cv. wait (lck); // The current thread is blocked. When the global flag bit is set to true, // The thread is awakened and the print thread id continues. std: cout <"thread" <id <'\ n';} void go () {std: unique_lock
Lck (CTX); ready = true; // you can specify true as the global flag. cv. notify_all (); // wake up all threads .} int main () {std: thread threads [10]; // spawn 10 threads: for (int I = 0; I <10; ++ I) threads [I] = std: thread (do_print_id, I); std: cout <"10 threads ready to race... \ n "; go (); // go! For (auto & th: threads) th. join (); return 0 ;}
Std: condition_variable_any Introduction
Andstd::condition_variableSimilar,std::condition_variable_anyOfwaitFunctions can accept anylockableParameters, whilestd::condition_variableOnly Acceptstd::unique_lock Parameter of the type, andstd::condition_variableAlmost identical.
std::cv_statusEnumeration type
cv_status::no_timeout wait_forOrwait_untilIf no timeout occurs, the thread receives a notification within the specified period.
Cv_status: timeout wait_for or wait_until timeout. Std: policy_all_at_thread_exit
Function prototype:
void notify_all_at_thread_exit (condition_variable& cond, unique_lock
lck);
When the thread that calls this function exits, allcondThe waiting thread on the condition variable will receive a notification. See the following example (reference ):
#include
// std::cout#include
// std::thread#include
// std::mutex, std::unique_lock#include
// std::condition_variablestd::mutex mtx;std::condition_variable cv;bool ready = false;void print_id (int id) { std::unique_lock
lck(mtx); while (!ready) cv.wait(lck); // ... std::cout << "thread " << id << '\n';}void go() { std::unique_lock
lck(mtx); std::notify_all_at_thread_exit(cv,std::move(lck)); ready = true;}int main (){ std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(print_id,i); std::cout << "10 threads ready to race...\n"; std::thread(go).detach(); // go! for (auto& th : threads) th.join(); return 0;}
Okay, so far, The two conditional variable classes in the header file (std::condition_variableAndstd::condition_variable_any), Enumeration type (std::cv_status) And auxiliary functions (std::notify_all_at_thread_exit().