您的位置:首页 > 编程语言 > C语言/C++

C++封装POSIX 线程库(二)条件变量的封装

2016-07-25 20:42 561 查看

C++封装POSIX 线程库(二)条件变量的封装

1.Pthread条件变量简介

条件变量也是线程间同步一个重要的内容,如果说互斥是一个种竞争关系,那么条件变量用于协调线程之间的关系,是一种合作关系。条件变量的应用很多,例如:
BlockingQueue
ThreadPool
等。

关于POSIX Pthread简介和示例用法可以参考:

POSIX Pthread 条件变量

2. 条件变量的封装

其实就是对
pthread_cond_t
和相关函数的封装:

#include <pthread.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//静态初始化

int pthread_cond_init(pthread_cond_t    *cond,    pthread_condattr_t *cond_attr);//动态初始化

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

int   pthread_cond_timedwait(pthread_cond_t   *cond,    pthread_mutex_t *mutex, const struct timespec *abstime);

int pthread_cond_destroy(pthread_cond_t *cond);


另外,我们在调用pthread_cond_wait的时候,必须先加锁,需要用到之前
MutexLock
的私用成员函数,这里已经在
MutexLock.h
中将
class Condition
设定为了
MutexLock
的一个友元。

//Condition.h

#ifndef __CONDITION_H__
#define __CONDITION_H__
#include "MutexLock.h"
#include <pthread.h>
#include <boost/noncopyable.hpp>
#include <assert.h>
class MutexLock;
class Condition
{
public:
Condition(MutexLock &mutex);
~Condition();
void wait();//封装pthread_cond_wait
void notify();//封装pthread_cond_signal
void notifyAll();//封装pthread_cond_broadcast
private:
pthread_cond_t cond_;
MutexLock &mutex_;
};
#endif


对成员函数分别进行初始化:

//Condition.cpp

#include "Condition.h"
#include "MutexLock.h"
#include <assert.h>

Condition::Condition(MutexLock &mutex):mutex_(mutex)
{
CHECK(!pthread_cond_init(&cond_, NULL));//条件变量初始化
}

Condition::~Condition()
{
CHECK(!pthread_cond_destroy(&cond_));//析构操作
}

void Condition::wait()
{
assert(mutex_.isLocking()); //wait前必须上锁
CHECK(!pthread_cond_wait(&cond_, mutex_.getMutexPtr()));
//pthread_cond_wait阻塞时释放锁,返回时会自动加锁
mutex_.restoreMutexStatus(); //还原状态
}

void Condition::notify()
{
CHECK(!pthread_cond_signal(&cond_));//通知等待线程队列中的线程
}

void Condition::notifyAll()
{
CHECK(!pthread_cond_broadcast(&cond_));//通知所有等待线程
}


在网上看到一个名词“惊群效应”,意思就是说
broadcast
使用不当,当唤醒所有线程而只有一个线程能够拿到资源,所以关于
broadcast
还是要慎用。

关于封装条件变量的一般使用,假设我们要实现简单的容量无限的
BlockingQueue
,可以这样写:

MutexLock mutex;
Condition cond(mutex);
std::deque<int> queue;

int dequeue()
{
MutexLockGurad lock(mutex);
while(queue.empty())
{
cond.wait();//这一步会释放mutex并进入等待,这两个操作是原子的
//wait()返回后,会自动重新加锁
}
assert(!queue.empty());
int top = queue.front();
queue.pop_front();
return top;
}

void enqueue(int x )
{
MutexLockGurad(mutex);
queue.push_back(x);
cond.notify();//这句也可以移出临界区
}


3. 参考

1.http://www.cnblogs.com/inevermore/p/4008397.html

2.《Linux多线程服务端编程—使用muduo网络库》

3.http://blog.csdn.net/zhangxiao93/article/details/51835470
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: