封装
condition的封装比较简单,因为Condition类内用到了MutexLock的私有成员,所以要在MutexLock类中声明为友元。
头文件
#ifndef _CONDITION_H_
#define _CONDITION_H_
#include "noncopyable.h"
#include <pthread.h>
class MutexLock; //前向声明 不需要包括MutexLock头文件
class Condition:public noncopyable{
public:
Condition(MutexLock& mutex);
~Condition();
void wait();
void notify();
void notifyAll();
private:
MutexLock& mutex_;
pthread_cond_t cond_;
};
源文件
#include "Condition.h"
#include "MutexLock.h"
Condition::Condition(MutexLock& mutex):mutex_(mutex){
CHECK(!pthread_cond_init(&cond_,NULL));
}
Condition::~Condition(){
CHECK(!pthread_cond_destroy(&cond_));
}
void Condition::wait(){
CHECK(!pthread_cond_wait(&cond_,mutex_.getMutexPtr()));
mutex_.restoreMutexStatus(); //Mutex私有成员
}
void Condition::notify(){
CHECK(!pthread_cond_signal(&cond_));
}
void Condition::notifyAll(){
CHECK(!pthread_cond_broadcast(&cond_));
}
使用
mutex的使用只有一种方式:
对于等待端:
- wait前先加锁
- 与布尔表达式一起使用,此表达式受mutex的保护
- 用while循环抱住布尔表达式
对于发送端:
- 不一定要在已上锁的情况下调用signal(理论上)
- signal之前一般要修改布尔表达式
- 修改布尔表达式通常要用mutex保护
- 注意signal和broadcast的区别
下面举个例子
此例中创建了两个消费者和一个生产者,生产者生产20个资源,两个消费者分别消费10个
#include <iostream>
#include "MutexLock.h"
#include <pthread.h>
#include <cstdlib>
#include <unistd.h>
#include <sys/syscall.h>
#include "Condition.h"
using namespace std;
const int num = 10;
int count=0;
MutexLock mutex;
Condition cond(mutex);
pid_t gettid(){
return syscall(__NR_gettid);
}
void* consume(void *arg){
pid_t tid = gettid();
for(int i=0;i<num;++i){
MutexLockGuard lock(mutex);
while(count == 0){
cond.wait();
}
cout<<"consume "<<tid<<": "<<count<<endl;
count--;
}
return arg;
}
void* produce(void* arg){
pid_t tid = gettid();
for(int i=0;i<2*num;++i){
MutexLockGuard lock(mutex);
count++;
cout<<"produce "<<tid<<": "<<count<<endl;
cond.notify();
}
return arg;
}
int main()
{
pthread_t tid[3];
pthread_create(&tid[0],NULL,produce,NULL);
pthread_create(&tid[1],NULL,consume,NULL);
pthread_create(&tid[2],NULL,consume,NULL);
for(int i=0;i<3;++i){
pthread_join(tid[i],NULL);
}
cout<<count<<endl;
}