頭文件condition_variable主要包括類condition_variable,類condition_variable_any,函數notify_all_at_thread_exit。
condition_variable
A condition_variable is an object able to block the calling thread until notified to resume.
當wait函數調用時,使用unique_lock鎖住當前線程。另一個線程在同一個condition_variable對象上調用一個通知函數時原線程被喚醒。
class condition_variable {
public:
condition_variable();
~condition_variable();
condition_variable(const condition_variable&) = delete;
condition_variable& operator=(const condition_variable&) = delete;
void notify_one() noexcept;
void notify_all() noexcept;
void wait(unique_lock<mutex>& lock);
template <class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred);
template <class Clock, class Duration>
cv_status wait_until(unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& abs_time);
template <class Clock, class Duration, class Predicate>
bool wait_until(unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& abs_time,
Predicate pred);
template <class Rep, class Period>
cv_status wait_for(unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& rel_time);
template <class Rep, class Period, class Predicate>
bool wait_for(unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& rel_time,
Predicate pred);
typedef implementation-defined native_handle_type;
native_handle_type native_handle();
};
void condition_variable::wait(unique_lock<mutex>& lock);
atomically unlocks lock, blocks the current executing thread, and adds it to the list of threads waiting on *this
. 當notify_all()或notify_one()被調用時,阻塞的線程會喚醒。線程也有可能“假醒”。當線程喚醒時,會對lock重新加鎖,然後wait函數返回。
notify_one()喚醒等待該條件的一個線程。如果沒有線程等待,該函數什麼也不做。如果多於一個線程在等待,選擇哪個線程是未定義的。
notify_all()喚醒等待該條件的所有線程。如果沒有線程等待,該函數什麼也不做。
然後看一個例子:
// 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::lock_guard<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
}
int main ()
{
// spawn 10 threads:
for (int i=0; i<10; ++i)
std::thread(print_id,i).detach();
std::cout << "10 threads ready to race...\n";
go();
// 等待其他線程執行完畢
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
帶有兩個參數的wait等價於
while (!pred()) {
wait(lock);
}
因此,上面例子中的while (!ready) cv.wait(lck);
可替換爲cv.wait(lck, []{return ready;});
。
wait_for和wait_until在定時時間到達時,如果還沒有被喚醒,它們會返回std::cv_status::timeout,在定時時間內被喚醒則返回std::cv_status::no_timeout。
enum class cv_status {
no_timeout,
timeout
};
wait_until的pred版等價於:
while (!pred())
if ( wait_until(lck,abs_time) == cv_status::timeout)
return pred();
return true;
wait_for的pred版等價於:
return wait_until (lck, chrono::steady_clock::now() + rel_time, std::move(pred));
notify_all_at_thread_exit
void notify_all_at_thread_exit( std::condition_variable& cond, std::unique_lock<std::mutex> lk );
notify_all_at_thread_exit 提供機制,通知其他線程給定的線程已完全完成,包括銷燬所有 thread_local 對象。它操作如下:
- 將先前獲得的鎖 lk 的所有權轉移到內部存儲。
- 修改執行環境,以令當前線程退出時,如同以下列方式通知其他線程:
lk.unlock();
cond.notify_all();
condition_variable_any
condition_variable_any是condition_variable的通用版本。
class condition_variable_any {
public:
condition_variable_any();
~condition_variable_any();
condition_variable_any(const condition_variable_any&) = delete;
condition_variable_any& operator=(const condition_variable_any&) = delete;
void notify_one() noexcept;
void notify_all() noexcept;
template <class Lock>
void wait(Lock& lock);
template <class Lock, class Predicate>
void wait(Lock& lock, Predicate pred);
template <class Lock, class Clock, class Duration>
cv_status wait_until(Lock& lock,
const chrono::time_point<Clock, Duration>& abs_time);
template <class Lock, class Clock, class Duration, class Predicate>
bool wait_until(Lock& lock,
const chrono::time_point<Clock, Duration>& abs_time,
Predicate pred);
template <class Lock, class Rep, class Period>
cv_status wait_for(Lock& lock,
const chrono::duration<Rep, Period>& rel_time);
template <class Lock, class Rep, class Period, class Predicate>
bool wait_for(Lock& lock,
const chrono::duration<Rep, Period>& rel_time,
Predicate pred);
};
以上主要參考自cppreference和cplusplus