生产者与消费模型
功能:解耦,支持忙闲不均,支持并发
三种关系:
- 生产者与生产者之间是互斥关系
- 消费者与消费者之间是互斥关系
- 生产者与消费者之间是同步+互斥关系
保证数据的安全:
- 同步:对临界资源操作的时候保证原子性
- 互斥:在供应的同时不能进行消费
版本1:基于链表结构
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#define CONSUMERS_COUNT 2
#define PRODUCERS_COUNT 2
//声明链表结构
struct msg{
struct msg *next;
int num;
};
struct msg *head = NULL;
//声明条件变量和互斥量
pthread_cond_t cond;
pthread_mutex_t mutex;
pthread_t threads[CONSUMERS_COUNT + PRODUCERS_COUNT];
void *consumer(void *p)
{
//将传参的内容拿出来并且释放原先的空间
int num = *(int*)p;
free(p);
struct msg *mp;
for(;;){
//保持唯一访问性互斥量加锁
pthread_mutex_lock(&mutex);
//如果没有内容可以消费,条件变量等待条件满足
while(head == NULL){
printf("%d begin wait a condition...\n", num);
pthread_cond_wait(&cond, &mutex);
}
//开始消费过程
printf("%d end wait a condition...\n", num);
printf("%d begin consume produce...\n", num);
mp = head;
head = mp->next;
//解锁并将消费过的内容存储空间进行释放
pthread_mutex_unlock(&mutex);
printf("Consume %d\n", mp->num);
free(mp);
printf("%d end consume product...\n", num);
sleep(rand() % 5);
}
}
void *producer(void *p)
{
//声明链表结构体
struct msg *mp;
//把数拿出来之后将原先传参的空间释放掉
int num = *(int*)p;
free(p);
for(;;){
printf("%d begin produce product...\n", num);
//为声明的结构体开辟空间并随机赋值
mp = (struct msg*)malloc(sizeof(struct msg));
mp->num = rand() % 1000 + 1;
printf("produce %d\n", mp->num);
//对其进行互斥量加锁
pthread_mutex_lock(&mutex);
//把刚刚生产的内容放在链表的表头
mp->next = head;
head = mp;
printf("%d end produce product...\n", num);
//条件变量唤醒等待
pthread_cond_signal(&cond);
//解锁
pthread_mutex_unlock(&mutex);
sleep(rand() % 5);
}
}
int main(void)
{
srand(time(NULL));
//创建互斥量和条件变量
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&mutex, NULL);
//生产过程
int i;
for(i = 0; i < CONSUMERS_COUNT; i++){
int *p = (int*)malloc(sizeof(int));
*p = i;
pthread_create(&threads[i], NULL, consumer, (void*)p);
}
//消费过程
for(i = 0; i < PRODUCERS_COUNT; i++){
int *p = (int*)malloc(sizeof(int));
*p = i;
pthread_create(&threads[CONSUMERS_COUNT + i], NULL, producer, (void*)p);
}
//线程等待
for(i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++)
pthread_join(threads[i], NULL);
//销毁互斥量和条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
版本2:基于数组环形结构
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
#define CONSUMERS_COUNT 1
#define PRODUCERS_COUNT 1
#define BUFFSIZE 10
int g_buffer[BUFFSIZE];
unsigned short in = 0;
unsigned short out = 0;
unsigned short produce_id = 0;
unsigned short consume_id = 0;
//声明生产者关注的空格子和消费者关注的满格子
sem_t g_sem_full;
sem_t g_sem_empty;
//声明互斥量
pthread_mutex_t g_mutex;
//什么一个线程数组
pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT];
//消费者函数
void* consume(void *arg)
{
//将传参拿出来并且释放原空间
int i;
int num = *(int*)arg;
free(arg);
while(1)
{
printf("%d wait buffer not empty\n", num);
//等待信号量,信号量的值会减1(初始状态下没有内容所以对sem_empty关注)
sem_wait(&g_sem_empty);
//对互斥量进行加锁
pthread_mutex_lock(&g_mutex);
for(i = 0; i < BUFFSIZE; i++){
printf("%d", i);
if(g_buffer[i] == -1)
printf("%s", "null");
else
printf("%d", g_buffer[i]);
if(i == out)
printf("\t<--consume");
printf("\n");
}
consume_id = g_buffer[out];
printf("%d begin consume product %d\n", num, consume_id);
g_buffer[out] = -1;
out = (out + 1) % BUFFSIZE;
printf("%d end consume product %d\n", num, consume_id);
//完成操作,解锁互斥量
pthread_mutex_unlock(&g_mutex);
//消费完成之后,对空格子进行+1操作
sem_post(&g_sem_full);
sleep(1);
}
return NULL;
}
//生产者函数
void* produce(void *arg)
{
int i;
//拿到传参并释放传参的空间
int num = *(int*)arg;
free(arg);
while(1)
{
printf("%d wait buffer not full\n", num);
//信号量等待,信号量-1
//生产者关注空格子,初始状态没有数据,所以关注sem_full
sem_wait(&g_sem_full);
pthread_mutex_lock(&g_mutex);
//轮询生产过程
for(i = 0; i < BUFFSIZE; i++)
{
printf("%d", i);
if(g_buffer[i] == -1)
printf("%s ", "null");
else
printf("%d", g_buffer[i]);
if(i == in)
printf("\t<--produce");
printf("\n");
}
printf("%d begin produce product %d\n", num, produce_id);
g_buffer[in] = produce_id;
in = (in + 1) % BUFFSIZE;
printf("%d end produce product %d\n", num, produce_id++);
pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_empty);
sleep(5);
}
return NULL;
}
int main(void)
{
int i;
for(i = 0; i < BUFFSIZE; i++)
g_buffer[i] = -1;
//初始化信号量
sem_init(&g_sem_full, 0, BUFFSIZE);
sem_init(&g_sem_empty, 0, 0);
//初始化互斥量
pthread_mutex_init(&g_mutex, NULL);
for(i = 0; i < CONSUMERS_COUNT; i++)
{
int *p = (int*)malloc(sizeof(int));
*p = i;
//创建消费者线程
pthread_create(&g_thread[i], NULL, consume, (void*)p);
}
for(i = 0; i < PRODUCERS_COUNT; i++)
{
int *p = (int*)malloc(sizeof(int));
*p = i;
//创建生产者线程
pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, \
(void*)p);
}
//线程等待,回收资源
for(i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++)
pthread_join(g_thread[i], NULL);
//销毁信号量和互斥量
sem_destroy(&g_sem_full);
sem_destroy(&g_sem_empty);
pthread_mutex_destroy(&g_mutex);
return 0;
}