c++ 条件变量

参考cplusplus
参考cppreference

1.condition_variable

  • 为std::unique_lock提供条件变量

1.1 wait/ wait_for / wait_until

//unconditional (1) 
void wait (unique_lock& lck);

//predicate (2) 
template 
  void wait (unique_lock& lck, Predicate pred);
  • 条件变量工作过程:
    step1.调用者把锁住的lck传给函数,函数然后自动把线程放到等待条件的线程列表上,然后对lck进行解锁。
    step2.一旦条件变量满足,wait返回时,函数解除阻塞,病重新多lck进行加锁。
    如果指定了谓词pred,函数只在pred为false才阻塞,并且通知只有在pred为true的时候才能解除阻塞。
// condition_variable::wait (with predicate)
#include            // std::cout
#include              // std::thread, std::this_thread::yield
#include               // std::mutex, std::unique_lock
#include  // 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 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 lck(mtx);
    cargo = i+1;
    cv.notify_one();
  }

  consumer_thread.join();

  return 0;
}
//unconditional (1) 
template 
  cv_status wait_for (unique_lock& lck,
                      const chrono::duration& rel_time);

//predicate (2) 
template 
       bool wait_for (unique_lock& lck,
                      const chrono::duration& rel_time, Predicate pred);
  • 版本1返回 cv_status::timeout或者cv_status::no_timeout;
    版本2返回pred()
// condition_variable::wait_for example
#include            // std::cout
#include              // std::thread
#include              // std::chrono::seconds
#include               // std::mutex, std::unique_lock
#include  // 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 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;
}
//unconditional (1) 
template 
  cv_status wait_until (unique_lock& lck,
                        const chrono::time_point& abs_time);

//predicate (2) 
template 
       bool wait_until (unique_lock& lck,
                        const chrono::time_point& abs_time,
                        Predicate pred);

1.2 notify_one / notify_all

void notify_one() noexcept;
  • 将等待该条件的一个线程取消阻塞。多余一个线程等待时,选择哪个线程是未指定的。
// condition_variable::notify_one
#include            // std::cout
#include              // std::thread
#include               // std::mutex, std::unique_lock
#include  // 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 lck(mtx);
  while (cargo==0) consume.wait(lck);
  std::cout << cargo << '\n';
  cargo=0;
  produce.notify_one();
}

void producer (int id) {
  std::unique_lock 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;
}
void notify_all() noexcept;
// condition_variable::notify_all
#include            // std::cout
#include              // std::thread
#include               // std::mutex, std::unique_lock
#include  // std::condition_variable

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void print_id (int id) {
  std::unique_lock lck(mtx);
  while (!ready) cv.wait(lck);
  // ...
  std::cout << "thread " << id << '\n';
}

void go() {
  std::unique_lock 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;
}

2.condition_variable_any

  • 为任何的lock类型提供条件变量
//unconditional (1) 
template  void wait (Lock& lck);

//predicate (2) 
template 
  void wait (Lock& lck, Predicate pred);
// condition_variable_any::notify_all
#include            // std::cout
#include              // std::thread
#include               // std::mutex
#include  // std::condition_variable_any

std::mutex mtx;
std::condition_variable_any cv;
bool ready = false;

void print_id (int id) {
  mtx.lock();
  while (!ready) cv.wait(mtx);
  // ...
  std::cout << "thread " << id << '\n';
  mtx.unlock();
}

void go() {
  mtx.lock();
  ready = true;
  cv.notify_all();
  mtx.unlock();
}

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;
}

3.notify_all_at_thread_exit

void notify_all_at_thread_exit (condition_variable& cond, unique_lock lck);
  • lck最好是右值
    在线程退出的时候类似于做了一下工作:
lck.unlock();
cond.notify_all()
// notify_all_at_thread_exit
#include            // std::cout
#include              // std::thread
#include               // std::mutex, std::unique_lock
#include  // std::condition_variable

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void print_id (int id) {
  std::unique_lock lck(mtx);
  while (!ready) cv.wait(lck);
  // ...
  std::cout << "thread " << id << '\n';
}

void go() {
  std::unique_lock lck(mtx);
  std::notify_all_at_thread_exit(cv,std::move(lck));
  ready = true;
}

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";

  std::thread(go).detach();   // go!

  for (auto& th : threads) th.join();

  return 0;
}

4.cv_status——前面有用到

enum class cv_status { no_timeout, timeout };

你可能感兴趣的:(c++ 条件变量)