條件變量類型
類 | wait 函數使用的鎖 |
---|---|
condition_variable | unique_lock<mutex> |
condition_variable_any | 任何種類的鎖/互斥量 |
一個線程調用條件變量的 wait 函數進行等待(阻塞),直到另一個線程調用同一個條件變量的 notify 函數將其喚醒。
condition_variable
構造
default (1) | condition_variable(); |
---|---|
copy [deleted] (2) | condition_variable (const condition_variable&) = delete; |
等待
wait
unconditional (1) | void wait (unique_lock<mutex>& lck); |
---|---|
predicate (2) | template <class Predicate> void wait (unique_lock<mutex>& lck, Predicate pred); |
在線程被阻塞的前一刻,wait 函數會自動調用 lck.unlock() 以允許其他線程可以獲取該鎖。
一旦線程被 notify 喚醒,該函數解除阻塞並自動調用 lck.lock() ,然後函數返回。
形式(2)中,只有當 pred 返回 false 時,wait 纔會阻塞,且在 notify 喚醒時,只有 pred 返回 true 纔會解除阻塞。它與以下實現類似:
while (!pred()) wait(lck);
當 wait 函數返回時,線程需要再次檢查條件是否成立,因爲可能存在虛假喚醒(即條件不成立,但還是被喚醒了)。
wait_for
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); |
和 wait() 類似,但是 wait_for() 返回的情況是:要麼被喚醒,要麼超時(等了 rel_time 時長)。
形式(1)超時時返回 cv_status::timeout
,否則返回 cv_status::no_timeout
。
形式(2)返回 pred() 。
wait_until
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); |
和 wait_for() 類似,只是超時時間以絕對時間指定。
// condition_variable::wait (with predicate)
#include <iostream>
#include <thread>
#include <mutex>
#include <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;
}
1
2
3
4
5
6
7
8
9
10
// condition_variable::wait_for example
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>
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):
.
.
7
You entered: 7
喚醒
喚醒一個等待線程 | void notify_one() noexcept; |
---|---|
喚醒所有等待線程 | void notify_all() noexcept; |
如果沒有線程在等待,則什麼都不做。
// condition_variable::notify_one
#include <iostream>
#include <thread>
#include <mutex>
#include <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
6
7
8
9
10
condition_variable_any
構造
default (1) | condition_variable_any(); |
---|---|
copy [deleted] (2) | condition_variable_any (const condition_variable_any&) = delete; |
等待
wait
unconditional (1) | template <class Lock> void wait (Lock& lck); |
---|---|
predicate (2) | template <class Lock, class Predicate> void wait (Lock& lck, Predicate pred); |
wait_for
unconditional (1) | template <class Lock, class Rep, class Period> cv_status wait_for (Lock& lck, const chrono::duration<Rep,Period>& rel_time); |
---|---|
predicate (2) | template <class Lock, class Rep, class Period, class Predicate> bool wait_for (Lock& lck, const chrono::duration<Rep,Period>& rel_time, Predicate pred); |
wait_until
unconditional (1) | template <class Lock, class Clock, class Duration> cv_status wait_until (Lock& lck, const chrono::time_point<Clock,Duration>& abs_time); |
---|---|
predicate (2) | template <class Lock, class Clock, class Duration, class Predicate> bool wait_until (Lock& lck, const chrono::time_point<Clock,Duration>& abs_time, Predicate pred); |
和 condition_variable 對應的函數類似。
喚醒
喚醒一個等待線程 | void notify_one() noexcept; |
---|---|
喚醒所有等待線程 | void notify_all() noexcept; |
如果沒有線程在等待,則什麼都不做。