Linux:生產者消費者模型下篇(基於環形隊列)

基於環形隊列的生產者消費者模型

上篇講解了生產者消費者模型以及基於BlockingQueue實現該模型,下篇這裏就實現一個基於環形隊列的生產者消費者模型吧!這個環形隊列用數組來實現。

1.如何把數組設置一個環形的隊列呢?
利用模運算來實現順序結構的環形操作。0 ~ 9模10依然是0 ~ 9,10模10就變成0了,也就回到了數組的頭部,從而實現一個環形隊列。

2.那麼如何判斷該環形隊列的空和滿呢?
剛開始的時候生產者和消費者指向同一塊空間,生產者在生產的時候,先判斷前面的格子裏是不是消費者,如果前面的格子裏不是消費者就在當前格子裏生產數據,然後++,如果前面的格子裏是消費者,那就不在當前的格子裏生產數據,保持不動。
假如現在有10個格子,下標爲0 ~ 9,消費者依然在0號格子,生產者生產到8號格子了,那麼生產者判斷9號格子不是消費者,於是在8號格子裏生產數據,然後++到9號格子,此時繼續判斷,生產者發現9號格子的下一個0號格子裏是消費者,所以此時生產者不再生產,表示該環形隊列已經滿了。所以我們採用浪費一個格子的操作實現了判空和判滿。

3.四條規則

  1. 消費者不能超過生產者(如果消費者快,但是生產者還沒生產完的時候,消費者就不能進行消費,消費者必須等生產者生產完)
  2. 生產者不能把消費者套一個圈(如果生產者快,而且隊列已經被生產者生產滿了,此時生產者就不能進行生產了,生產者此時就必須等消費者消費完才能繼續生產)
  3. 環形隊列爲空的時候,生產者先出發
  4. 環形隊列爲滿的時候,消費者先出發

4.怎麼實現?
引入兩個信號量,一個記錄格子資源個數,另一個記錄數據資源個數。
生產者生產的時候要申請空格子(P格子:格子資源數減一),那麼生產完畢之後有數據的格子就會多一個(V數據:數據資源數加一)。
消費者消費的時候就是要拿取有數據的格子(P數據:數據資源數減一),那麼消費完畢之後空格子就會多一個(V格子:格子資源數加一)

具體實現代碼解釋:
在這裏插入圖片描述
運行結果:
此時生產者生產的快,因此會迅速把環形隊列生產滿,滿了之後基於信號量的同步和互斥它就不能生產了,因此消費者開始每隔一秒消費一條數據,當消費者消費完一條數據之後,格子信號量就會增加1,因此生產者又會快馬加鞭的生產一條數據,消費者再隔一秒消費一條數據,生產者還是窮追不捨的又生產一條數據,因此看到的結果是生產者迅速生產滿之後,就變成了消費一條生產一條。
在這裏插入圖片描述
代碼如下:

  1 #include <iostream>
  2 #include <pthread.h>
  3 #include <stdlib.h>
  4 #include <time.h>
  5 #include <semaphore.h>
  6 #include <unistd.h>
  7 #define NUM 16
  8 class ring{
  9     private:
 10         int Ring[NUM];
 11         sem_t blank_sem;
 12         sem_t data_sem;
 13         int p_step;
 14         int c_step;
 15     public:
 16         void P(sem_t *sem)
 17         {
 18             sem_wait(sem);
 19         }
 20         void V(sem_t *sem)
 21         {
 22             sem_post(sem);
 23         }
 24     public:
 25         ring()
 26             :p_step(0),c_step(0)
 27         {
 28             sem_init(&blank_sem,0,NUM);
 29             sem_init(&data_sem,0,0);
 30         }
 31         void PushData(const int &data)
 32         {
 33             P(&blank_sem);
 34             Ring[p_step]=data;
 35             p_step++;
 36             p_step%=NUM;
 37             V(&data_sem);
 38         }
 39         void PopData(int &data)
 40         {
 41             P(&data_sem);
 42             data=Ring[c_step];
 43             c_step++;
 44             c_step%=NUM;
 45             V(&blank_sem);
 46         }
 47         ~ring()
 48         {
 49             sem_destroy(&blank_sem);
 50             sem_destroy(&data_sem);
 51         }
 52 };
 53 void *product(void *arg)
 54 {
 55     ring *r=(ring *)arg;
 56     srand((unsigned long)time(NULL));
 57     while(1)
 58     {
 59         int data=rand()%100+1;
 60         r->PushData(data);
 61         std::cout<<"product done:"<<data<<std::endl;
 62     }
 63 }
 64 void *consume(void *arg)
 65 {
 66     ring *r=(ring *)arg;
 67     while(1)
 68     {
 69         int data;
 70         r->PopData(data);
 71         std::cout<<"consume done:"<<data<<std::endl;
 72         sleep(1);
 73     }
 74 }
 75 int main()
 76 {
 77     ring r;
 78     pthread_t p,c;
 79     pthread_create(&p,NULL,product,(void *)&r);
 80     pthread_create(&c,NULL,consume,(void *)&r);
 81     pthread_join(p,NULL);
 82     pthread_join(c,NULL);
 83     return 0;
 84 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章