c++11線程支持庫:condition_variable

頭文件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);
};

以上主要參考自cppreferencecplusplus

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章