条件变量

条件变量

条件变量简介

条件变量(condition variable)是为了等待某个条件成立而设计,提供一种线程间通知机制,在条件成立之前,等待线程进入睡眠状态,当某个条件成立时,信号端发射signal/broadcast来“唤醒”等待线程。

pthread条件变量相关的函数主要有以下5个:

#include <pthread.h>
int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr* cond_attr);
int pthread_cond_destroy(pthread_cond_t* cond);
int pthread_cond_broadcast(pthread_cond_t* cond);
int pthread_cond_signal(pthread_cond_t* cond);
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex* mutex);

以上函数均以返回0表示成功,非0表示出错。

条件变量的资源申请分为静态和动态两种,分别为:

  • pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 使用宏将条件变量各个字段初始化为0
  • 调用pthread_cond_init/pthread_cond_destroy为动态初始化和销毁条件变量资源

条件变量的使用

条件变量需结合互斥量(mutex)一起使用。pthread_cond_wait等待条件成立时需配备一个mutex来保护等待操作的原子性,调用pthread_cond_wait之前,需确保mutex已经加锁,否则将导致不可预期行为。pthread_cond_wait函数执行时,首先将mutex解锁,然后判断条件是否成立,待该等待函数成功返回后,mutex重新被加锁。

条件变量是一个或多个线程等待某个布尔表达式为真,下面推荐打开条件变量正确的姿势。

对于wait端:

  1. 必须与mutex一起使用,该布尔表达式的读写操作受此mutex保护;
  2. 在调用pthread_cond_wait之前必须先对mutex加锁;
  3. 把判断布尔条件和wait操作放在while循环中,而非if语句中

对于signal/broadcast端:

  1. 不一定在mutex上锁的情况下调用signal;
  2. 在signal之前一般需要修改布尔表达式;
  3. 修改布尔表达式需要mutex保护;
  4. 注意区分signal和broadcast。
MutexLock mtx;
Condition cond(mtx);
std::deque<int> queue;

// wait端
int Dequeue() {
  MutexLockGuard lk(mtx);
  while(queue.empty()) {
    cond.Wait();
  }
  assert(!queue.empty());
  int top = queue.front();
  queue.pop_front();
  return top;
}

// signal端
void Enqueue(int x) {
  MutexLockGuard lk(mtx);
  queue.push_back(x);
  cond.notify();
}

参考:

【1】《Linux多线程服务器编程》——陈硕

【2】《UNP》

posted @ 2019-06-22 14:10  bigosprite  阅读(941)  评论(0编辑  收藏  举报