生產者與消費模型
功能:解耦,支持忙閒不均,支持併發
三種關係:
- 生產者與生產者之間是互斥關係
- 消費者與消費者之間是互斥關係
- 生產者與消費者之間是同步+互斥關係
保證數據的安全:
- 同步:對臨界資源操作的時候保證原子性
- 互斥:在供應的同時不能進行消費
版本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;
}