生產者消費者模型
爲何要使用生產者消費者模型
生產者消費者模式就是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞隊列來進行通訊,所以生產者生產完數據之後不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列裏取,阻塞隊列就相當於一個緩衝區,平衡了生產者和消費者的處理能力。這個阻塞隊列就是用來給生產者和消費者解耦的。
321原則
3:三種關係:生產者和生產者之間,消費者和消費者之間是互斥關係
生產者和消費者之間是同步關係
2:兩種角色:生產者和消費者
1:一個交易場所
生產者消費者模型優點
- 解耦
- 支持併發
- 支持忙閒不均
基於Blockingqueue的生產者消費者模型
生產者線程往阻塞隊列裏生產數據,消費者線程從阻塞隊列裏讀取數據。
運行結果:
結果就是生產者往阻塞隊列裏生產一條數據,然後生產者通知消費者來進行消費,然後消費者就從該阻塞隊列中讀取數據,如果阻塞隊列裏沒有數據,那麼消費者就會掛起等待,等待生產者生產完畢。
整個過程不會出現生產者還沒生產消費者就來進行數據的讀取,或者阻塞隊列裏沒有數據但是消費者一直在進行數據的讀取這樣的效率問題。因爲加了mutex互斥量保證了在同一時間只能有一個線程對臨界資源進行訪問,其他線程無法進入。同時加了cond條件變量,保證了生產者和消費者之間按照一定的順序去訪問臨街資源,提高了整個過程的效率。
代碼如下:
1 #include <iostream>
2 #include <time.h>
3 #include <stdlib.h>
4 #include <pthread.h>
5 #include <unistd.h>
6 #include <queue>
7 class BlockQueue{
8 private:
9 std::queue<int> q;
10 pthread_mutex_t lock;
11 pthread_cond_t cond;
12 private:
13 void LockQueue(){
14 pthread_mutex_lock(&lock);
15 }
16 void UnlockQueue(){
17 pthread_mutex_unlock(&lock);
18 }
19 void WakeupOneThread()
20 {
21 pthread_cond_signal(&cond);
22 }
23 void ThreadWait(){
24 pthread_cond_wait(&cond,&lock);
25 }
26 bool IsEmpty(){
27 return q.size()==0?true:false;
28 }
29 public:
30 BlockQueue()
31 {
32 pthread_mutex_init(&lock,NULL);
33 pthread_cond_init(&cond,NULL);
34 }
35 void PushData(const int &data)
36 {
37 LockQueue();
38 q.push(data);
39 UnlockQueue();
40 std::cout<<"product run down,data push success:"<<data<<" wake up one thread down..."<<std::endl;
41 WakeupOneThread();
42 }
43 void PopData(int &data)
44 {
45 LockQueue();
46 while(IsEmpty())
47 {
48 ThreadWait();
49 }
50 data=q.front();
51 q.pop();
52 UnlockQueue();
53 std::cout<<"consume run done,data pop success:"<<data<<std::endl;
54 }
55 ~BlockQueue()
56 {
57 pthread_mutex_destroy(&lock);
58 pthread_cond_destroy(&cond);
59 }
60 };
61 void *product(void *arg)
62 {
63 BlockQueue *bq=(BlockQueue *)arg;
64 srand((unsigned long)time(NULL));
65 while(1)
66 {
67 int data=rand()%100+1;
68 bq->PushData(data);
69 sleep(1);
70 }
71 }
72 void *consume(void *arg)
73 {
39 UnlockQueue();
40 std::cout<<"product run down,data push success:"<<data<<" wake up one thread down..."<<std::endl;
41 WakeupOneThread();
42 }
43 void PopData(int &data)
44 {
45 LockQueue();
46 while(IsEmpty())
47 {
48 ThreadWait();
49 }
50 data=q.front();
51 q.pop();
52 UnlockQueue();
53 std::cout<<"consume run done,data pop success:"<<data<<std::endl;
54 }
55 ~BlockQueue()
56 {
57 pthread_mutex_destroy(&lock);
58 pthread_cond_destroy(&cond);
59 }
60 };
61 void *product(void *arg)
62 {
63 BlockQueue *bq=(BlockQueue *)arg;
64 srand((unsigned long)time(NULL));
65 while(1)
66 {
67 int data=rand()%100+1;
68 bq->PushData(data);
69 sleep(1);
70 }
71 }
72 void *consume(void *arg)
73 {
39 UnlockQueue();
40 std::cout<<"product run down,data push success:"<<data<<" wake up one thread down..."<<std::endl;
41 WakeupOneThread();
42 }
43 void PopData(int &data)
44 {
45 LockQueue();
46 while(IsEmpty())
47 {
48 ThreadWait();
49 }
50 data=q.front();
51 q.pop();
52 UnlockQueue();
53 std::cout<<"consume run done,data pop success:"<<data<<std::endl;
54 }
55 ~BlockQueue()
56 {
57 pthread_mutex_destroy(&lock);
58 pthread_cond_destroy(&cond);
59 }
60 };
61 void *product(void *arg)
62 {
63 BlockQueue *bq=(BlockQueue *)arg;
64 srand((unsigned long)time(NULL));
65 while(1)
66 {
67 int data=rand()%100+1;
68 bq->PushData(data);
69 sleep(1);
70 }
71 }
72 void *consume(void *arg)
73 {
74 BlockQueue *bq=(BlockQueue *)arg;
75 while(1)
76 {
77 int d;
78 bq->PopData(d);
79 }
80 }
81 int main()
82 {
83 BlockQueue bq;
84 pthread_t p,c;
85 pthread_create(&p,NULL,product,(void *)&bq);
86 pthread_create(&c,NULL,consume,(void *)&bq);
87
88 pthread_join(p,NULL);
89 pthread_join(c,NULL);
90 return 0;
91 }