利用條件變量實現多線程生產者消費者問題

以下程序實現linux多線程下一個生產者多個消費者的問題。

 

  1. /* 
  2. 使用條件變量時,線程在不滿足條件時會被掛起。 
  3. 在消費品都消費完畢,生產者線程停止生產後, 
  4. 消費者線程因爲緩衝區內容爲空,將一直掛起。 
  5. 需設置一個全局變量start,當生產者已經停止時,需告知其他消費者解除掛起的狀態。 
  6. */ 
  7.  
  8. #include <stdio.h>   
  9. #include <stdlib.h>   
  10. #include <string.h>   
  11. #include <pthread.h>   
  12. #define NUMS 10000  //表示生產,消費的次數   
  13. #define CAPACITY 50 //定義緩衝區最大值   
  14. int capacity = 0; //當前緩衝區的產品個數   
  15. pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;//互斥量   
  16. pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;//條件變量   
  17.  
  18. int start = 0; 
  19.    
  20. void *produce(void *args)   
  21. {   
  22.     int i = 0;   
  23.     for (; i < NUMS; )   
  24.     {   
  25.         pthread_mutex_lock(&mylock);//加鎖   
  26.         if (capacity >= CAPACITY) //當前產品個數大於等於緩衝區最大值,則不把產品放入緩衝區。   
  27.         {   
  28.             printf("緩衝區已滿,無法放入產品\n");   
  29.             pthread_cond_wait(&mycond, &mylock); 
  30.         } else {//將產品放入緩衝區   
  31.             ++capacity;   
  32.             printf("生產者存入一個產品, 緩衝區大小爲:%d\n", capacity);   
  33.             i++;   
  34.         }   
  35.         pthread_mutex_unlock(&mylock);   
  36.         pthread_cond_broadcast(&mycond); 
  37.     }   
  38.      
  39.     pthread_mutex_lock(&mylock);//加鎖   
  40.     printf("生產者finish!!!!\n");   
  41.     start = 1; 
  42.     pthread_mutex_unlock(&mylock);  
  43.     pthread_cond_broadcast(&mycond); 
  44.  
  45.     return ((void *) 0);   
  46. }   
  47.    
  48. void * consume(void *args)   
  49. {   
  50.     int i = 0;   
  51.     char *p = (char*)args; 
  52.      
  53.     printf("消費者%s start!!!!!!!!!\n", p);   
  54.     for (; i < NUMS; )   
  55.     {   
  56.         pthread_mutex_lock(&mylock);   
  57.         if (capacity > 0)    
  58.         {   
  59.             --capacity;   
  60.             printf("消費者%s消耗一個產品,緩衝區大小爲:%d\n", p, capacity);   
  61.             i++;   
  62.         }  
  63.         else if(capacity <= 0 && start != 1)         
  64.         { //當沒獲取到資源時,將被wait掛起。當其他線程退出後,將不會有broadcast對wait進行解除。 
  65.           //這將導致循環未結束的線程掛起。所以需引入下一個分支的判斷 
  66.   
  67.             printf("%s 緩衝區已空,無法消耗產品\n", p);   
  68.             pthread_cond_wait(&mycond, &mylock); 
  69.               
  70.         }  
  71.         else if(capacity <= 0 && start == 1)  
  72.         {//start爲1,說明生產者進程已經停止,所以應該釋放鎖,同時,跳出循環,結束線程。 
  73.             pthread_mutex_unlock(&mylock);   
  74.             //pthread_cond_broadcast(&mycond);//可以不加??? 
  75.             break
  76.         } 
  77.  
  78.         pthread_mutex_unlock(&mylock);   
  79.         pthread_cond_broadcast(&mycond); 
  80.     }   
  81.  
  82.     pthread_mutex_lock(&mylock);   
  83.     printf("消費者%s finish!!!!!!!!!\n", p);   
  84.     pthread_cond_broadcast(&mycond); 
  85.  
  86.     pthread_mutex_unlock(&mylock);   
  87.     return ((void *) 0);   
  88. }   
  89.    
  90. #define CNUM 5 
  91.  
  92. int main(int argc, char** argv) {   
  93.    
  94.     int err;   
  95.     pthread_t produce_tid;   
  96.     pthread_t consume_tid[CNUM];   
  97.     void *ret;   
  98.     err = pthread_create(&produce_tid, NULL, produce, NULL);//創建線程   
  99.     if (err != 0)    
  100.     {   
  101.         printf("線程producer創建失敗:%s\n", strerror(err));   
  102.         exit(-1);   
  103.     }   
  104.  
  105.     int i = 0; 
  106.     char *pfree[CNUM] = {0}; 
  107.  
  108.     for(i= 0; i < CNUM; i++) 
  109.     { 
  110.         char* pc = NULL; 
  111.         pc = (char*)malloc(sizeof(char) * (strlen("consumer") + 2)); 
  112.         sprintf(pc, "consumer%d", i); 
  113.         pfree[i] = pc; 
  114.  
  115.         err = pthread_create(consume_tid + i, NULL, consume, (void*)pc);   
  116.         if (err != 0)   
  117.         {   
  118.             printf("線程consumer創建失敗:%s\n", strerror(err));   
  119.             continue
  120.             //exit(-1);   
  121.         }   
  122.     } 
  123.  
  124.     err = pthread_join(produce_tid, &ret);//主線程等到子線程退出   
  125.     if (err != 0)    
  126.     {   
  127.         printf("生產着線程分解失敗:%s\n", strerror(err));   
  128.         exit(-1);   
  129.     }   
  130.  
  131.     for(i= 0; i < CNUM; i++) 
  132.     { 
  133.         free(pfree[i]); 
  134.         err = pthread_join(consume_tid[i], NULL);   
  135.         if (err != 0)   
  136.         {   
  137.             printf("消費者線程分解失敗:%s\n", strerror(err));   
  138.             continue;   
  139.         }   
  140.     } 
  141.     return (EXIT_SUCCESS);   
  142. }   

 

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