生产者消费者模型
为何要使用生产者消费者模型
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
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 }