概念
同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问
题,叫做同步
竞态条件:因为时序问题,而导致程序异常,我们称之为竞态条件。
条件变量:当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。
条件变量函数
初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict
attr);
参数:
cond:要初始化的条件变量
attr:NULL
销毁
int pthread_cond_destroy(pthread_cond_t *cond)
等待条件满足
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数:
cond:要在这个条件变量上等待
mutex:互斥量
唤醒等待
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
signal:唤醒一个在该条件等待的线程
broadcast:唤醒所以在该条件等待的线程
为什么 pthread_cond_wait 需要互斥量?
条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等下去都不会满足,所以必须要有一个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足,并且友好的通知等待在条件 变量上的线程。
条件不会无缘无故的突然变得满足了,必然会牵扯到共享数据的变化。所以一定要用互斥锁来保护。没有 互斥锁就无法安全的获取和修改共享数据。
正确使用
pthread_mutex_lock(&mutex);
while (条件为假)
pthread_cond_wait(cond, mutex);
修改条件
pthread_mutex_unlock(&mutex);
阻塞队列
#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>
#include<cstdlib>
#include<ctime>
#include<unistd.h>
using namespace std;
#define SIZE 10
template<class T>
class blockQueue
{
public:
blockQueue(int cap = SIZE):_cap(cap)
{
pthread_mutex_init(&_conMutex,nullptr);
pthread_mutex_init(&_proMutex,nullptr);
pthread_cond_init(&_conCond,nullptr);
pthread_cond_init(&_proCond,nullptr);
}
//生产者
void push(const T& val)
{
//生产者加锁
proLock();
// 判断同步条件
while(isFull())
{
//等待条件满足
waitofPro();
}
//生成数据
creatVal(val);
//解锁
prounLock();
//唤起消费者
wakeupCon();
}
T pop()
{
//消费者加锁
conLock();
// 判断同步条件
while(isEmpty())
{
//等待条件满足
waitofCon();
}
//消费数据
T tmp = getVal();
//解锁
conunLock();
//唤起生产者
wakeupPro();
return tmp;
}
~blockQueue()
{
pthread_mutex_destroy(&_conMutex);
pthread_mutex_destroy(&_proMutex);
pthread_cond_destroy(&_conCond);
pthread_cond_destroy(&_proCond);
}
private:
//消费者加锁
void conLock()
{
pthread_mutex_lock(&_conMutex);
}
//消费者解锁
void conunLock()
{
pthread_mutex_unlock(&_conMutex);
}
bool isEmpty()
{
return _bq.empty();
}
//等待条件满足
void waitofCon()
{
pthread_cond_wait(&_conCond,&_conMutex);
}
//唤醒生产者
void wakeupPro()
{
pthread_cond_signal(&_proCond);
}
T getVal()
{
T tmp = _bq.front();
_bq.pop();
return tmp;
}
//生产者加锁
void proLock()
{
pthread_mutex_lock(&_proMutex);
}
//生产者解锁
void prounLock()
{
pthread_mutex_unlock(&_proMutex);
}
bool isFull()
{
return _bq.size()==_cap;
}
//等待条件满足
void waitofPro()
{
pthread_cond_wait(&_proCond,&_proMutex);
}
void creatVal(const T& val)
{
_bq.push(val);
}
//唤醒消费者
void wakeupCon()
{
pthread_cond_signal(&_conCond);
}
queue<T> _bq; //阻塞队列
int _cap; // 大小
pthread_mutex_t _conMutex; // 消费者锁
pthread_mutex_t _proMutex; // 生成者锁
pthread_cond_t _conCond; // 消费者同步条件
pthread_cond_t _proCond; // 生成者同步条件
};