Condition Variable
初始化和销毁
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER
pthread_cond_init
函数初始化一个Condition Variable,attr
参数为NULL
则表示缺省属性。
pthread_cond_destroy
函数销毁一个Condition Variable。
- 如果Condition Variable是静态分配的,也可以用宏定义
PTHEAD_COND_INITIALIZER
初始化,相当于用pthread_cond_init
函数初始化并且attr
参数为NULL
。
- 成功返回0,失败返回错误号。
等待和通知
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
- 一个Condition Variable总是和一个Mutex搭配使用的。一个线程可以调用
pthread_cond_wait
在一个Condition Variable上阻塞等待,这个函数做以下三步操作:
- 释放Mutex。
- 阻塞等待。
- 当被唤醒时,重新获得Mutex并返回。
pthread_cond_timedwait
函数还有一个额外的参数可以设定等待超时,如果到达了abstime
所指定的时刻仍然没有别的线程来唤醒当前线程,就返回ETIMEDOUT
。
- 一个线程可以调用
pthread_cond_signal
唤醒在某个Condition Variable上等待的另一个线程。
- 调用
pthread_cond_broadcast
唤醒在这个Condition Variable上等待的所有线程。
源码
Condition.h
#pragma once
#include "Mutex.h"
#include <pthread.h>
namespace muduo
{
class Condition
{
public:
Condition(MutexLock& mutex) : mutex_(mutex)
{
MCHECK(pthread_cond_init(&pcond_,NULL));
}
~Condition()
{
MCHECK(pthread_cond_destroy(&pcond_));
}
void wait()
{
//@ pthread_cond_wait will release mutex
MutexLock::UnassignGuard ug(mutex_);
MCHECK(pthread_cond_wait(&pcond_, mutex_.get_mutex()));
}
//@ returns true if time out, false otherwise.
bool wait_for_seconds(double seconds);
void notify()
{
MCHECK(pthread_cond_signal(&pcond_));
}
void notify_all()
{
MCHECK(pthread_cond_broadcast(&pcond_));
}
private:
MutexLock& mutex_;
pthread_cond_t pcond_;
};
}
Condition.cc
#include "Condition.h"
namespace muduo
{
//@ returns true if time out, false otherwise.
bool Condition::wait_for_seconds(double seconds)
{
struct timespec abs_time;
clock_gettime(CLOCK_REALTIME,&abs_time);
const int64_t kNanoSecondsPerSecond = 1000000000;
int64_t nano_seconds = static_cast<int64_t>(seconds * kNanoSecondsPerSecond);
abs_time.tv_sec += static_cast<time_t>((abs_time.tv_sec + nano_seconds) / kNanoSecondsPerSecond);
abs_time.tv_nsec += static_cast<long>((abs_time.tv_sec + nano_seconds) % kNanoSecondsPerSecond);
MutexLock::UnassignGuard ug(mutex_);
return ETIMEDOUT == pthread_cond_timedwait(&pcond_,mutex_.get_mutex(),&abs_time);
}
}