@[TOC]生产者-消费者问题
生产者-消费者问题
生产者-消费者问题:
一群生产者在生产消息,并将此消息提供给消费者去消费。它们中间设了具有N个缓存区的缓冲池,生产者每次可将生产的消息放入一个缓存区内,消费者每次可将一个缓存区内的消息拿出来消费。但这个过程有两个条件:任何一方操作一个缓冲区时不能有其它同时对该缓冲区进行操作;只有当缓冲区还有空余,生产者才能生产,只有当缓冲区至少有一个产品,消费者才能从中取出来消费。这里两个条件分别对应了互斥和同步。
如上图所示便是生产者-消费者模型,它是利用存储中介隔离生产者和消费者的交互,相比直通而言,它的好处在于:不必相互等待,提高运行效率。
实现思路
运用所学的线程互斥锁和条件变量来实现此模型。
对于生产者而言:
(1)先上锁
(2)如果存储中介中元素大于或等于存储最大数量,则不需要生产,则阻塞于此,释放锁;反之,则生产,
(3)在收到可生产条件信号之后,便唤醒进程,判断是否可生产,(可能只需要生产一件,但唤醒了多个线程)
(4)生产结束后,释放锁
对于消费者者而言:
(1)先上锁
(2)如果存储中介中元素小于或等于0,则不能消费,则阻塞于此,释放锁;反之,则消费,
(3)在收到可消费条件信号之后,便唤醒进程,判断是否可消费,(可能只能消费一件,但唤醒了多个线程)
(4)消费结束后,释放锁
实现代码
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
typedef struct Store{ //存储缓冲区结构体
char things[10];
int cnt;
}Store;
Store s;
pthread_mutex_t mutex; //互斥锁类型
pthread_cond_t notfull; //缓冲区未满(可生产)信号
pthread_cond_t notempty;//缓冲区未空(可消费)信号
void *proc(void *arg) { //product 生产
while(1){
pthread_mutex_lock(&mutex); //上锁
while(s.cnt >= 10) { //必须用while 不能用if
pthread_cond_wait(¬full,&mutex); //等待 并释放锁
}
char c = rand()%26+'A';
s.things[s.cnt++] = c;
size_t i;
for(i = 0;i < s.cnt;i++) {
printf("%c ",s.things[i]);
}
printf("\n");
printf("放入:%c\n",c);
pthread_cond_signal(¬empty); //生产后必定可消费 发出可消费条件信号
pthread_mutex_unlock(&mutex); // 解锁
usleep(rand()%100000);
}
}
void *cust(void *arg) { //消费
while(1){
pthread_mutex_lock(&mutex);//上锁
while(s.cnt <= 0) {
pthread_cond_wait(¬empty,&mutex);
}
size_t i;
for(i = 0;i < s.cnt;i++) {
printf("%c ",s.things[i]);
}
printf("\n");
char c = s.things[--s.cnt];
printf("取出:%c\n",c);
pthread_cond_signal(¬full);//消费后必定可生产 发出可生产信号
pthread_mutex_unlock(&mutex);//解锁
usleep(rand()%100000);
}
}
int main() {
srand(time(NULL));
pthread_t ids[6];
pthread_mutex_init(&mutex,NULL); // 互斥量初始化
pthread_cond_init(¬full,NULL); // 条件变量初始化
pthread_cond_init(¬empty,NULL);
size_t i;
for(i = 0;i < 6;i++) {
if(i%2 == 0) {
pthread_create(&ids[i],NULL,proc,NULL);
}else{
pthread_create(&ids[i],NULL,cust,NULL);
}
}
getchar();
return 0;
}