C++ 條件變量

條件變量類型

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;

如果沒有線程在等待,則什麼都不做。

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