// condition_variable example #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock #include <condition_variable> // std::condition_variable std::mutex mtx; std::condition_variable cv; bool ready = false; void print_id (int id) { std::unique_lock<std::mutex> lck(mtx); while (!ready) cv.wait(lck); // ... std::cout << "thread " << id << '\n'; } void go() { std::unique_lock<std::mutex> lck(mtx); ready = true; cv.notify_all(); } 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"; go(); // go! for (auto& th : threads) th.join(); return 0; }
輸出:ios
10 threads ready to race... thread 5 thread 6 thread 0 thread 9 thread 4 thread 1 thread 3 thread 2 thread 8 thread 7
void notify_one() noexcept;
併發
// condition_variable::notify_one #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock #include <condition_variable> // std::condition_variable std::mutex mtx; std::condition_variable produce,consume; int cargo = 0; // shared value by producers and consumers void consumer () { std::unique_lock<std::mutex> lck(mtx); while (cargo==0) consume.wait(lck); std::cout << cargo << '\n'; cargo=0; produce.notify_one(); } void producer (int id) { std::unique_lock<std::mutex> lck(mtx); while (cargo!=0) produce.wait(lck); cargo = id; consume.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; }
輸出:函數
1 2 3 4 5 7 6 9 10 8
void notify_all() noexcept;
this
// condition_variable::notify_all #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock #include <condition_variable> // std::condition_variable std::mutex mtx; std::condition_variable cv; bool ready = false; void print_id (int id) { std::unique_lock<std::mutex> lck(mtx); while (!ready) cv.wait(lck); // ... std::cout << "thread " << id << '\n'; } void go() { std::unique_lock<std::mutex> lck(mtx); ready = true; cv.notify_all(); } 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"; go(); // go! for (auto& th : threads) th.join(); return 0; }
輸出:atom
10 threads ready to race... thread 7 thread 4 thread 3 thread 2 thread 0 thread 1 thread 6 thread 5 thread 8 thread 9
unconditional (1) void wait (unique_lock<mutex>& lck); predicate (2) template <class Predicate> void wait (unique_lock<mutex>& lck, Predicate pred);
若是指定了 pred(2), 則該函數僅在 pred 返回 false 時調用 wait 纔會阻塞當前線程,而且通知只能在線程變爲 true 時才取消阻塞線程(這對檢查虛假喚醒調用特別有用)spa
while (!pred()) wait(lck);
參數說明
lck線程
predcode
反覆調用它,直到評估值爲 true。對象
// condition_variable::wait (with predicate) #include <iostream> // std::cout #include <thread> // std::thread, std::this_thread::yield #include <mutex> // std::mutex, std::unique_lock #include <condition_variable> // std::condition_variable std::mutex mtx; std::condition_variable cv; int cargo = 0; bool shipment_available() {return cargo!=0;} void consume (int n) { for (int i=0; i<n; ++i) { std::unique_lock<std::mutex> lck(mtx); cv.wait(lck,shipment_available); // consume: std::cout << cargo << '\n'; cargo=0; } } int main () { std::thread consumer_thread (consume,10); // produce 10 items when needed: for (int i=0; i<10; ++i) { while (shipment_available()) std::this_thread::yield(); std::unique_lock<std::mutex> lck(mtx); cargo = i+1; cv.notify_one(); } consumer_thread.join(); return 0; }
輸出:ip
1 2 3 4 5 6 7 8 9 10
unconditional (1) template <class Rep, class Period> cv_status wait_for (unique_lock<mutex>& lck, const chrono::duration<Rep,Period>& rel_time); predicate (2) template <class Rep, class Period, class Predicate> bool wait_for (unique_lock<mutex>& lck, const chrono::duration<Rep,Period>& rel_time, Predicate pred);
return wait_until (lck, chrono::steady_clock::now() + rel_time, std::move(pred));
// condition_variable::wait_for example #include <iostream> // std::cout #include <thread> // std::thread #include <chrono> // std::chrono::seconds #include <mutex> // std::mutex, std::unique_lock #include <condition_variable> // std::condition_variable, std::cv_status std::condition_variable cv; int value; void 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 (read_value); std::mutex mtx; std::unique_lock<std::mutex> lck(mtx); while (cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout) { std::cout << '.' << std::endl; } std::cout << "You entered: " << value << '\n'; th.join(); return 0; }
輸出:
Please, enter an integer (I'll be priniting dots): . . 2 You entered: 2
unconditional (1) template <class Clock, class Duration> cv_status wait_until (unique_lock<mutex>& lck, const chrono::time_point<Clock,Duration>& abs_time); predicate (2) template <class Clock, class Duration, class Predicate> bool wait_until (unique_lock<mutex>& lck, const chrono::time_point<Clock,Duration>& abs_time, Predicate pred);
while (!pred()) if ( wait_until(lck,abs_time) == cv_status::timeout) return pred(); return true;
參數:abs_time
#include <iostream> #include <atomic> #include <condition_variable> #include <thread> #include <chrono> using namespace std::chrono_literals; std::condition_variable cv; std::mutex cv_m; std::atomic<int> i{0}; void waits(int idx) { std::unique_lock<std::mutex> lk(cv_m); auto now = std::chrono::system_clock::now(); if(cv.wait_until(lk, now + idx*100ms, [](){return i == 1;})) std::cerr << "Thread " << idx << " finished waiting. i == " << i << '\n'; else std::cerr << "Thread " << idx << " timed out. i == " << i << '\n'; } void signals() { std::this_thread::sleep_for(120ms); std::cerr << "Notifying...\n"; cv.notify_all(); std::this_thread::sleep_for(100ms); i = 1; std::cerr << "Notifying again...\n"; cv.notify_all(); } int main() { std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals); t1.join(); t2.join(); t3.join(); t4.join(); }
輸出:
Thread 1 timed out. i == 0 Notifying... Thread 2 timed out. i == 0 Notifying again... Thread 3 finished waiting. i == 1