浅析生产者与消费者模型

 生产者与消费模型

功能:解耦,支持忙闲不均,支持并发

三种关系:

  1. 生产者与生产者之间是互斥关系
  2. 消费者与消费者之间是互斥关系
  3. 生产者与消费者之间是同步+互斥关系

保证数据的安全:

  • 同步:对临界资源操作的时候保证原子性
  • 互斥:在供应的同时不能进行消费

 

版本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;
    
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章