相关函数
#include <pthread.h> /*头文件*/
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); /*初始化一个互斥锁*/
int pthread_mutex_destroy(pthread_mutex_t *mutex);/*注销一个互斥锁*/
int pthread_mutex_lock(pthread_mutex_t *mutex); /*加锁,不成功,阻塞等待*/
int pthread_mutex_unlock(pthread_mutex_t *mutex);/*解锁*/
int pthread_join(pthread_t th,void *thread_return); /*等待线程结束*/
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);/*初始化条件变量*/
pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex); /*基于条件变量阻塞,无条件等待*/
pthread_cond_signal(pthread_cond_t *cond); /*解除特定线程阻塞,存在多个线程按入队顺序激活激活其中一个*/
pthread_cond_destory(pthread_cond_t *cond); /*清除条件变量*/
模型分析
- 生产者产生数据并放入缓冲区,缓冲区满,生产者阻塞。
- 消费者提取缓冲区中的数据,缓冲区空,消费者阻塞。
- 缓冲区未满且不空,生产者与消费者处于一种动态平衡的过程。
伪代码
- 根据模型分析,两个线程同时指向了相同的缓冲区域,为了保护数据的完整性,所以必须使用互斥锁。
/*生产者*/
put_info(...)
{
加锁保护数据;
while(缓冲区已满)
生产者等待;
生产者开始生产数据;
解锁数据;
给消费者发送信号;
}
/*消费者*/
get_info(...)
{
加锁保护数据;
while(缓冲区为空)
消费者等待;
消费者开始提取数据;
解锁数据;
给生产者发送信号;
}
实现过程
基本结构
#define BUFFER_SIZR 4 //规定缓冲区大小
#define OVER -1 //定义结束标志
typedef struct producers{
int buf[BUFFER_SIZR]; //定义缓冲区
pthread_mutex_t mutex; //定义互斥量
int readpos,writepos; //定义读端和写端
pthread_cond_t full; //定义条件变量
pthread_cond_t empty;
}PRODUCER;
具体代码实现
void init(PRODUCER *p) /*初始化*/
{
pthread_mutex_init(&p->mutex,NULL);
pthread_cond_init(&p->empty,NULL);
pthread_cond_init(&p->full,NULL);
p->readpos = 0;
p->writepos = 0;
}
void put(PRODUCER *p,int data) /*将数据写入缓冲区*/
{
pthread_mutex_lock(&p->mutex);
while((p->writepos+1) % BUFFER_SIZR == p->readpos) //判断缓冲区是否已满
{
pthread_cond_wait(&p->full,&p->mutex);
}
p->buf[p->writepos++] = data; //缓冲区写入数据
if(p->writepos >= BUFFER_SIZR) //读端置零
p->writepos = 0;
pthread_mutex_unlock(&p->mutex);
pthread_cond_signal(&p->empty); //给消费者发送信号
}
int get(PRODUCER *p) /*获得缓冲区中的数据*/
{
int data;
pthread_mutex_lock(&p->mutex);
while(p->readpos == p->writepos) //缓冲区是否为空
pthread_cond_wait(&p->empty,&p->mutex);
data = p->buf[p->readpos++]; //缓冲区读出数据
if(p->readpos >= BUFFER_SIZR) //写端置零
p->readpos = 0;
pthread_mutex_unlock(&p->mutex);
pthread_cond_signal(&p->full); //给生产者发送信号
return data;
}
PRODUCER buffer;
void *producer(void * data) /*生产者输入数据*/
{
int n;
for(n = 0;n<10;n++)
{
printf("==生产者%d\n",n);
put(&buffer,n);
}
put(&buffer,OVER); //结束标志
}
void* consumer(void * data) /*消费者获得数据*/
{
int d;
while(1)
{
d = get(&buffer);
if(d == OVER) //遇到结束标志,退出
break;
printf("--消费者%d\n",d);
}
}
void destory(PRODUCER *p) /*销毁*/
{
pthread_mutex_destroy(&p->mutex);
pthread_cond_destroy(&p->empty);
pthread_cond_destroy(&p->full);
}
int main (int argc,char * argv[])
{
pthread_t thid1,thid2;
void * ret;
init(&buffer);
pthread_create(&thid1,NULL,(void*)&producer,NULL); //创建相应线程
pthread_create(&thid2,NULL,(void*)&consumer,NULL);
pthread_join(thid1,&ret); //等待线程结束
pthread_join(thid2,&ret);
destory(&buffer);
return 0;
}
输出结果:
问题总结
当然除了条件变量和互斥锁,我们还可以通过信号量完成该模型的设计,大致思路都是一样的,信号量可以说是互斥锁的升级版,它可以实现多线程同时访问同一个数据区域,功能很强大,有兴趣的小伙伴可以自己试着实现哦。
文章难免有错误和不足的地方,欢迎小伙伴的提出和指正。