以下程序實現linux多線程下一個生產者多個消費者的問題。
- /*
- 使用條件變量時,線程在不滿足條件時會被掛起。
- 在消費品都消費完畢,生產者線程停止生產後,
- 消費者線程因爲緩衝區內容爲空,將一直掛起。
- 需設置一個全局變量start,當生產者已經停止時,需告知其他消費者解除掛起的狀態。
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <pthread.h>
- #define NUMS 10000 //表示生產,消費的次數
- #define CAPACITY 50 //定義緩衝區最大值
- int capacity = 0; //當前緩衝區的產品個數
- pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;//互斥量
- pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;//條件變量
- int start = 0;
- void *produce(void *args)
- {
- int i = 0;
- for (; i < NUMS; )
- {
- pthread_mutex_lock(&mylock);//加鎖
- if (capacity >= CAPACITY) //當前產品個數大於等於緩衝區最大值,則不把產品放入緩衝區。
- {
- printf("緩衝區已滿,無法放入產品\n");
- pthread_cond_wait(&mycond, &mylock);
- } else {//將產品放入緩衝區
- ++capacity;
- printf("生產者存入一個產品, 緩衝區大小爲:%d\n", capacity);
- i++;
- }
- pthread_mutex_unlock(&mylock);
- pthread_cond_broadcast(&mycond);
- }
- pthread_mutex_lock(&mylock);//加鎖
- printf("生產者finish!!!!\n");
- start = 1;
- pthread_mutex_unlock(&mylock);
- pthread_cond_broadcast(&mycond);
- return ((void *) 0);
- }
- void * consume(void *args)
- {
- int i = 0;
- char *p = (char*)args;
- printf("消費者%s start!!!!!!!!!\n", p);
- for (; i < NUMS; )
- {
- pthread_mutex_lock(&mylock);
- if (capacity > 0)
- {
- --capacity;
- printf("消費者%s消耗一個產品,緩衝區大小爲:%d\n", p, capacity);
- i++;
- }
- else if(capacity <= 0 && start != 1)
- { //當沒獲取到資源時,將被wait掛起。當其他線程退出後,將不會有broadcast對wait進行解除。
- //這將導致循環未結束的線程掛起。所以需引入下一個分支的判斷
- printf("%s 緩衝區已空,無法消耗產品\n", p);
- pthread_cond_wait(&mycond, &mylock);
- }
- else if(capacity <= 0 && start == 1)
- {//start爲1,說明生產者進程已經停止,所以應該釋放鎖,同時,跳出循環,結束線程。
- pthread_mutex_unlock(&mylock);
- //pthread_cond_broadcast(&mycond);//可以不加???
- break;
- }
- pthread_mutex_unlock(&mylock);
- pthread_cond_broadcast(&mycond);
- }
- pthread_mutex_lock(&mylock);
- printf("消費者%s finish!!!!!!!!!\n", p);
- pthread_cond_broadcast(&mycond);
- pthread_mutex_unlock(&mylock);
- return ((void *) 0);
- }
- #define CNUM 5
- int main(int argc, char** argv) {
- int err;
- pthread_t produce_tid;
- pthread_t consume_tid[CNUM];
- void *ret;
- err = pthread_create(&produce_tid, NULL, produce, NULL);//創建線程
- if (err != 0)
- {
- printf("線程producer創建失敗:%s\n", strerror(err));
- exit(-1);
- }
- int i = 0;
- char *pfree[CNUM] = {0};
- for(i= 0; i < CNUM; i++)
- {
- char* pc = NULL;
- pc = (char*)malloc(sizeof(char) * (strlen("consumer") + 2));
- sprintf(pc, "consumer%d", i);
- pfree[i] = pc;
- err = pthread_create(consume_tid + i, NULL, consume, (void*)pc);
- if (err != 0)
- {
- printf("線程consumer創建失敗:%s\n", strerror(err));
- continue;
- //exit(-1);
- }
- }
- err = pthread_join(produce_tid, &ret);//主線程等到子線程退出
- if (err != 0)
- {
- printf("生產着線程分解失敗:%s\n", strerror(err));
- exit(-1);
- }
- for(i= 0; i < CNUM; i++)
- {
- free(pfree[i]);
- err = pthread_join(consume_tid[i], NULL);
- if (err != 0)
- {
- printf("消費者線程分解失敗:%s\n", strerror(err));
- continue;
- }
- }
- return (EXIT_SUCCESS);
- }