生產者-消費者問題是最經典的操作系統同步與互斥相結合的問題。生活中的很多問題,要麼是它的變形,要麼是它的簡化。
本篇博客的實現方法是用linux版本的線程互斥鎖+線程信號量來實現該問題。
問題場景:m個生產者,n個消費者,大小爲k的緩衝區。
1、互斥保證:對緩衝區的操作是互斥的。用互斥鎖(pthread_mutex_t)實現。
2、同步保證:當緩衝區爲空時,消費者阻塞;當緩衝區爲滿時,生產者阻塞。用線程信號量(sem_t)實現。
編程細節:
1、信號量的初始化:緩衝區初始爲空,因此生產者的初始信號量值爲k,消費者的初始信號量值爲0.
2、先獲取互斥鎖,然後才能獲取信號量。否則會造成死鎖。
3、生產者、消費者分別需要一個變量idx來記錄可以當前自己可處理的位置。
#include <stdio.h>
#include <pthread.h> //多線程、互斥鎖所需頭文件
#include <semaphore.h> //線程信號量所需頭文件
//設置生產者、消費者、緩衝區的個數
#define M 10
#define N 10
#define K 10
#define X 10
//互斥鎖
pthread_mutex_t mutex;
//信號量
sem_t pro;
sem_t con;
//緩衝區和生產者、消費者的遊標
int buffer[K] = {0};
int pro_idx = 0;
int con_idx = 0;
void *producer(void *)
{
for(int i=0;i<X;i++)
{
sem_wait(&pro);
pthread_mutex_lock(&mutex);
int tmp = buffer[pro_idx];
printf("Produce at buffer[%d] : from %d to 1\n", pro_idx, tmp);
buffer[pro_idx] = 1;
pro_idx = (pro_idx+1) % K;
pthread_mutex_unlock(&mutex);
sem_post(&con);
}
return NULL;
}
void *consumer(void *)
{
for(int i=0;i<X;i++)
{
sem_wait(&con);
pthread_mutex_lock(&mutex);
int tmp = buffer[con_idx];
printf("Consumer at buffer[%d] : from %d to 0\n", con_idx, tmp);
buffer[con_idx] = 0;
con_idx = (con_idx+1) % K;
pthread_mutex_unlock(&mutex);
sem_post(&pro);
}
return NULL;
}
int main(int argc, const char * argv[])
{
//聲明線程標識符
pthread_t producer_thread[M];
pthread_t consumer_thread[N];
//初始化線程信號量:初始時爲緩衝區全空
sem_init(&pro, 0, K);
sem_init(&con, 0, 0);
//初始化互斥鎖:下面初始化兩種方式都可以
mutex = PTHREAD_MUTEX_INITIALIZER;
//pthread_mutex_init(&mutex, NULL);
for (int i=0; i<M; i++)
{
if (pthread_create(&producer_thread[i], NULL, producer, NULL))
printf("Producer Thread Cannot Created.\n");
}
for(int i=0;i<N;i++)
{
if(pthread_create(&consumer_thread[i], NULL, consumer, NULL))
printf("Consumer Thread Cannot Created.\n");
}
for(int i=0;i<M;i++)
pthread_join(producer_thread[i], NULL);
for(int i=0;i<N;i++)
pthread_join(consumer_thread[i], NULL);
return 0;
}