淺析生產者與消費者模型

 生產者與消費模型

功能:解耦,支持忙閒不均,支持併發

三種關係:

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

 

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