生产者消费者模型
简单来说就是“321原则(并非某一规则,而是为了理解生产者消费者模型)”
“3”代表的是三种关系
生产者与消费者的互斥与同步关系
生产者与生产者的互斥(或竞争)关系
消费者与消费者的互斥(或竞争)关系
“2”代表两种角色
生产者:往交易场所放东西(在计算机中一般都是数据)的人
消费者:从交易场所取东西的人
“1”代表一个交易场所
所谓交易场所就是内存中具有存储数据的一段有界缓冲区
综上,给出生产者消费者模型的描述:两个进程共享一个缓冲区,一个进程称为生产者向缓冲区中放数据,另一个称为消费者从缓冲取中取数据,当缓冲区中被放时,生产者进程就必须可进入挂起状态,直到消费者从缓冲中取走数据时,生产者才能继续向缓冲区中存放数据,同样当缓冲取中没有数据时,消费者进程就必须进入挂起休眠状态,直到生产者向缓冲区中放入数据时,消费者才能被唤醒继续从缓冲区中取走数据。
图示:

基于链表的生产者消费者模型
分析:当使用链表来模拟生产者消费者模型时,我们可以借助链表的插入来扮演生产者的角色,用链表的删除来充当消费者的角色,为了便于实现,我们直接采用链表的头插和链表的头删操作来模拟放数据和取数据这两个过程。

(1)条件变量接口说明
-
<span style="font-family:Microsoft YaHei;font-size:18px;">int pthread_cond_wait(pthread_cond_t* redtrist cond , pthread_mutex_t* redtrist )//挂起等待</span>
1、不满足条件时必须进行休眠(释放Mutex)
2、不能抱着锁资源休眠(进行阻塞式等待)
3、能被唤醒(被唤醒时能够重新获得Mutex资源并等待)
-
<span style="font-family:Microsoft YaHei;font-size:18px;">int pthread_cond_signal(pthread_cond_t* cond ) //唤醒</span>
1、生产者生产好数据之后通知消费者来消费数据
2、消费者消费完数据后通知生产者前来生产
(2)锁相关接口说明
-
<span style="font-family:Microsoft YaHei;font-size:18px;">int pthread_mutex_lock(pthread_mutex_t *mutex);</span>
阻塞式加锁
-
<span style="font-family:Microsoft YaHei;font-size:18px;">int pthread_mutex_trylock(pthread_mutex_t *mutex);</span>
非阻塞式加锁
-
<span style="font-family:Microsoft YaHei;font-size:18px;">int pthread_mutex_unlock(pthread_mutex_t *mutex);</span>
解锁,无论是阻塞式的加锁还是非阻塞式的加锁都需要使用此函数进行解锁
基于单链表的生产者消费者模型实现
-
<span style="font-family:Microsoft YaHei;font-size:18px;">#include<stdio.h>
-
#include<pthread.h>
-
#include<stdlib.h>
-
-
typedef struct list
-
{
-
int data;
-
struct list* next;
-
}list,*plist,**pplist;
-
-
plist head;
-
-
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
-
-
plist alloc_node(int d,plist l)
-
{
-
plist tmp=(plist)malloc(sizeof(list));
-
if(!tmp){
-
perror("malloc");
-
exit(1);
-
}
-
tmp->data=d;
-
tmp->next=l;
-
return tmp;
-
}
-
-
void initlist(pplist l){
-
*l=alloc_node(0,NULL);
-
}
-
-
int isempty(plist l){
-
return l->next==NULL?1:0;
-
}
-
-
void free_node(plist l){
-
if(l!=NULL){
-
free(l);
-
l=NULL;
-
}
-
}
-
-
void push_front(plist l,int d){
-
plist tmp=alloc_node(d,NULL);
-
tmp->next=l->next;
-
l->next=tmp;
-
}
-
-
void pop_front(plist l,int* out)
-
{
-
if(!isempty(l)){
-
plist tmp=l->next;
-
l->next=tmp->next;
-
*out=tmp->data;
-
free_node(tmp);
-
}
-
}
-
-
void showlist(plist l)
-
{
-
plist start=l->next;
-
while(start){
-
printf("%d ",start->data);
-
start=start->next;
-
}
-
printf("\n");
-
}
-
-
void destroy(plist l){
-
int data;
-
while(!isempty(l)){
-
pop_front(l,&data);
-
}
-
free_node(l);
-
}
-
-
void* consume(void* arg){
-
pthread_mutex_t* lockp=(pthread_mutex_t*)arg;
-
int data=0;
-
while(1){
-
pthread_mutex_lock(lockp);
-
if(isempty(head)){
-
pthread_cond_wait(&cond,&lockp);
-
}
-
pop_front(head,&data);
-
printf("consum done: %d\n",data);
-
pthread_mutex_unlock(lockp);
-
pthread_cond_signal(&cond);
-
}
-
}
-
void* product(void* arg){
-
pthread_mutex_t* lockp=(pthread_mutex_t*)arg;
-
int data=0;
-
while(1){
-
pthread_mutex_lock(lockp);
-
data=rand()%1234;
-
push_front(head,data);
-
printf("product done: %d\n",data);
-
pthread_mutex_unlock(lockp);
-
-
pthread_cond_signal(&cond);
-
}
-
}
-
-
int main()
-
{
-
pthread_mutex_t lock;
-
pthread_mutex_init(&lock,NULL);
-
-
initlist(&head);
-
pthread_t consumer,producter;
-
pthread_create(&consumer,NULL,consume,(pthread_mutex_t *)&lock);
-
pthread_create(&producter,NULL,product,(pthread_mutex_t *)&lock);
-
-
pthread_join(consumer,NULL);
-
pthread_join(producter,NULL);
-
destroy(head);
-
pthread_mutex_destroy(&lock);
-
return 0;
-
}</span>