首先介紹下單個生產者和消費者模型
首先創建一個環,環分爲無數格子,其規則是:
消費者永遠追不上生產者
生產者永遠追不上消費者,更別說套圈
形成兩類角色,一個環形buf
假設有n個格子 :生產者的範圍是[n,0];
消費者的範圍是[0,n];
首先編輯Makefile
ring.c
需要引入的頭文件
生產者
消費者
主函數
運行結果;
現在實現多生產者、消費者
生產者-消費者模型是指:
1. 生產者進行生產將物品放入倉庫,同一時間只能有一個生產者將物品放入倉庫,如果倉庫滿,生產者等待。
2. 消費者從倉庫中取出物品,同一時間只能有一個消費者取出物品,如果倉庫空,消費者等待;
3. 生產者將物品放入倉庫時消費者不能同時取;
4. 消費者取物品時生產者不能放入物品;
互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源,如“第一類讀寫者模型”。
總之,就是生產者羣體或消費者羣體內部是互斥的,兩個羣體之間是同步的。
當只有一個生產者、消費者時,由於同一羣體內部不需要互斥,所以只需在羣體之間實 現同步即可。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define N 2 // 消費者或者生產者的數目
#define M 10 // 緩衝數目
int in = 0; // 生產者放置產品的位置
int out = 0; // 消費者取產品的位置
int buff[M] = {0}; // 緩衝初始化爲0, 開始時沒有產品
sem_t empty_sem; // 同步信號量, 當滿了時阻止生產者放產品
sem_t full_sem; // 同步信號量, 當沒產品時阻止消費者消費
pthread_mutex_t mutex; // 互斥信號量, 一次只有一個線程訪問緩衝
int product_id = 0; //生產者id
int prochase_id = 0; //消費者id
/* 打印緩衝情況 */
void print()
{
int i;
for(i = 0; i < M; i++)
printf("%d ", buff[i]);
printf("/n");
}
/* 生產者方法 */
void *product()
{
int id = ++product_id;
while(1)
{
// 用sleep的數量可以調節生產和消費的速度,便於觀察
sleep(1);
//sleep(1);
sem_wait(&empty_sem);
pthread_mutex_lock(&mutex);
in = in % M;
printf("product%d in %d. like: /t", id, in);
buff[in] = 1;
print();
++in;
pthread_mutex_unlock(&mutex);
sem_post(&full_sem);
}
}
/* 消費者方法 */
void *prochase()
{
int id = ++prochase_id;
while(1)
{
// 用sleep的數量可以調節生產和消費的速度,便於觀察
sleep(1);
//sleep(1);
sem_wait(&full_sem);
pthread_mutex_lock(&mutex);
out = out % M;
printf("prochase%d in %d. like: /t", id, out);
buff[out] = 0;
print();
++out;
pthread_mutex_unlock(&mutex);
sem_post(&empty_sem);
}
}
int main()
{
pthread_t id1[N];
pthread_t id2[N];
int i;
int ret[N];
// 初始化同步信號量
int ini1 = sem_init(&empty_sem, 0, M);
int ini2 = sem_init(&full_sem, 0, 0);
if(ini1 && ini2 != 0)
{
printf("sem init failed /n");
exit(1);
}
//初始化互斥信號量
int ini3 = pthread_mutex_init(&mutex, NULL);
if(ini3 != 0)
{
printf("mutex init failed /n");
exit(1);
}
// 創建N個生產者線程
for(i = 0; i < N; i++)
{
ret[i] = pthread_create(&id1[i], NULL, product, (void *)(&i));
if(ret[i] != 0)
{
printf("product%d creation failed /n", i);
exit(1);
}
}
//創建N個消費者線程
for(i = 0; i < N; i++)
{
ret[i] = pthread_create(&id2[i], NULL, prochase, NULL);
if(ret[i] != 0)
{
printf("prochase%d creation failed /n", i);
exit(1);
}
}
//銷燬線程
for(i = 0; i < N; i++)
{
pthread_join(id1[i],NULL);
pthread_join(id2[i],NULL);
}
exit(0);
}
這個程序容易出錯誤的就是設置同步信號量和互斥信號量的順序出錯, 如在生產者或者消費者方法中把互斥信號量放在同步信號量的外層. 這樣在內層中某個sem_wait不一定能通過, 從而造成死鎖現象.
在多個消費者和一個消費者的不同就是是否需要互斥鎖。