消费者模型
消费者模型由消费者,生产者以及交易场所构成;消费者与生产者是两个线程,对公共存储空间进行访问
其中消费者与生产者的关系有以下几种:
- 消费者—消费者:互斥
- 消费者—生产者:互斥、同步
- 生产者—生产者:互斥
基于单链表的消费者模型
互斥关系的由互斥锁来实现:
int pthread_mutex_lock(pthread_mutex_t *mutex);//上锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁
//以上三个函数成功返回0;
等待则由以下函数实现:
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);//由time控制的等待
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);//阻塞式等待
测试用例:
由一个单向链表实现消费模型,建立两个线程,分别对链表进行头插,头删操作;模拟生产,消费情景:在实现互斥关系时,用互斥锁操作。最终实现:生产者生产一条数据(在链表中头插一个节点,并在屏幕上打印节点中数据),消费者跟着消费一条数据(打印链表节点中的数据)。以下是测试代码:
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<malloc.h>
pthread_mutex_t mutex_lock=PTHREAD_MUTEX_INITIALIZER;//init lock
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;//init cond
ypedef struct SeqList
{
int data;
struct SeqList* next;
}SeqList;
SeqList* list=NULL;
SeqList* Buynode(int d)
{
SeqList* list=(SeqList*)malloc(sizeof(SeqList));
list->data=d;
list->next=NULL;
return list;
}
void PushFront(SeqList **pplist,int d)
{
SeqList* tmp=Buynode(d);
tmp->next=*pplist;
*pplist=tmp;
}
int PopFront(SeqList** pplist)
{
if(*pplist==NULL)
{
return ;
}
SeqList* tmp=(*pplist)->next;
int ret=(*pplist)->data;
free(*pplist);
*pplist=tmp;
return ret;
}
void *product(void *arg)
{
while(1)
{
int d=rand()/9527;
int i=pthread_mutex_lock(&mutex_lock);//申请锁
if(i!=0)
{
pthread_cond_wait(&cond,&mutex_lock);//阻塞式等待
}
PushFront(&list,d);
printf("product %d\n",d);
pthread_mutex_unlock(&mutex_lock);//释放锁
sleep(1);
}
}
void *consume(void *arg)
{
while(1)
{
sleep(1);
int i=pthread_mutex_lock(&mutex_lock);//申请锁
int ret=PopFront(&list);
if(i!=0)
{
pthread_cond_wait(&cond,&mutex_lock);//等待
}
printf("consume %d\n",ret);
pthread_mutex_unlock(&mutex_lock);//释放锁
}
}
int main()
{
pthread_t t_a;//定义线程
pthread_t t_b;
pthread_create(&t_a,NULL,product,(void*)NULL);//确定线程入口点
pthread_create(&t_b,NULL,consume,(void*)NULL);
pthread_join(t_b,NULL);//等待线程退出
pthread_mutex_destroy(&mutex_lock);//销毁锁
pthread_cond_destroy(&cond);//销毁条件变量
return 0;
}
测试结果

基于环形队列的生产消费模型
在测试用例中先规定格子数为4,生产者先生产(打印生产好的数据),消费者每隔一秒消费一次(读取数据并打印)

实现条件
- 生产者不能超过消费者一圈
- 消费者永远跟在生产者后面
测试代码
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
#define SIZE 4
int arr[SIZE]={0};
int ret = 0;
sem_t datasem;
sem_t blanksem;
void *product(void *arg)
{
int i=0;
while(1)
{
sem_wait(&blanksem);//有格子资源时,生产者开始生产
arr[ret]=i;
printf("product done! %d\n", arr[ret]);
sem_post(&datasem);//给消费者发出数据资源信号
i++;
ret++;
ret %= SIZE;
}
}
void *consume(void *arg)
{
while(1)
{
sem_wait(&datasem);//申请,当有数据资源时,消费者开始消费
printf("consume done! %d\n", arr[ret]);
sem_post(&blanksem);//释放,并给生产者发出格子空出信号
sleep(1);
}
}
int main()
{
pthread_t c;//定义线程
pthread_t p;
sem_init(&datasem, 0, 0);//初始化信号量
sem_init(&blanksem,0, SIZE);
pthread_create(&p, NULL, product, NULL);//确定线程入口
pthread_create(&c, NULL, consume, NULL);
pthread_join(c, NULL);//等待线程退出
pthread_join(p, NULL);
sem_destroy(&datasem);//销毁信号量
sem_destroy(&blanksem);
return 0;
}
测试结果

以上测试结果可以看出,在生产了四个数据之后,消费者开始消费,直到消费完空出格子,生产者开始生产,等着每隔一秒消费者消费后,生产者接着生产。
在编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库
若有不正之处,恳请留言指正
本文介绍两种生产消费模型的实现方式,一种基于单链表,通过互斥锁和条件变量实现线程间的同步与互斥;另一种基于环形队列,利用信号量控制生产者与消费者的协调工作。
172万+

被折叠的 条评论
为什么被折叠?



