封装:信号量、互斥锁、条件变量
将这三者进行封装,使其实现RAII,省去初始化和销毁的过程。代码更简洁。
用在整个程序的方方面面。
1. 信号量:
支持P(获取),V(放回)操作
持有一个信号量S,S是一个自然数,
- P操作,如果S的值大于0,则将其减一;若S的值为0,则挂起执行。
- V操作,如果有其他进行因为等待S而挂起,则唤醒;若没有,则将S值加一。
和碗柜里的碗一样,S代表碗的数量,P代表拿碗,V代表放回碗,碗柜里的碗的数量是一开始确定的。如果拿光了,还有人要P,那就要等别人V了之后才能P,不然就要等。
#include <semaphore.h>
class sem
{
public:
sem(); //默认初始化,碗柜里的碗为0
sem(int num); //碗柜里的碗为num个
~sem(); //销毁
bool wait(); //拿碗
bool post(); //放回
private:
sem_t m_sem; //semaphore.h提供给的信号量,我们要做的就是把对他的操作封装一下。
};
2. 互斥锁
互斥锁,也成互斥量,可以保护关键代码段,以确保独占式访问.当进入关键代码段,获得互斥锁将其加锁;离开关键代码段,唤醒等待该互斥锁的线程。
class locker
{
public:
locker(); //初始化锁
~locker(); //销毁锁
bool lock(); //上锁
bool unlock(); //开锁
pthread_mutex_t *get(); //获取锁
private:
pthread_mutex_t m_mutex;
};
//用于局部区域的加锁和解锁
//进入区域就加锁,离开区域就解锁。
class MutexLockGuard{
public:
//初始化等同于上锁
MutexLockGuard(locker &mutex):m_mutex(mutex){
m_mutex.lock();
}
//销毁等同于解锁
~MutexLockGuard(){
m_mutex.unlock();
}
private:
locker &m_mutex;
};
3. 条件变量
条件变量提供了一种线程间的通知机制,当某个共享数据达到某个值时,唤醒等待这个共享数据的线程。
class cond
{
public:
cond();//初始化
~cond();//销毁
bool wait(pthread_mutex_t *m_mutex); //等待某个信号
bool timewait(pthread_mutex_t *m_mutex, struct timespec t);//一定时间内等,超过这个时间就不等了。
bool signal();//单独通知一个在等的,具体哪一个要看实现。
bool broadcast();//通知全部
private:
pthread_cond_t m_cond;
};