问题的提出
在我们对一些全局变量的进行非原子性操作的时候就可能出现非线程安全,比如我们吃面的问题。
我们做面的人就是生产者,吃面的人就是我们的消费者,当我们的消费者需要吃面的时候就唤醒我们的生产者进行生产,当我们有面的时候我们的生产者就不继续生产面条,去唤醒我们的消费者进行消费。
生产者和消费者模型:
- 如何保证生产者与消费者的线程安全?
- 生产者与生产者应该具有互斥关系
- 消费者与消费者之间应该具有互斥关系
- 生产者和消费者之间应该具有同步与互斥
实现生产者和消费者模型:
- 一个场所:
一个场所就是我们多个线程能够同时操作的,比如一个全局变量的链表或者一个类中的队列等等
- 两种角色:
两种角色是我们的生产者和消费者
- 三种关系:
三种关系就是生产者与生产者、消费者与消费者、生产者和消费者时间的关系
代码实现:
特别指出:因为促使条件满足之后,pthread_con_singnal唤醒至少一个等待线程,导致因为条件的判断是一个if语句而造成一碗面多吃的情况,第一个吃面的人加锁吃面之后解锁,第二个吃面的人被唤醒继续吃面,此时条件的判断需要使用while,因为促使条件满足后,othrad_cond_wait唤醒是所有等待在条件变量线程,但是有可能唤醒的线程也是一个坐满的线程,因为已经有面条,条件不满足而陷入等待,导致死等,本质的原因就是唤醒了错误的角色。(因为不同的角色等待在统一条件变量上);
1 #include <iostream>
2 #include <queue>
3 #include <stdlib.h>
4 #include <unistd.h>
5 class Blockqueue{
6 public:
7 //构造函数,初始化我们的锁和队列的大小
8 Blockqueue(int cap = 10):_capcity(cap){
9 pthread_mutex_init(&_mutex,NULL);
10 pthread_cond_init(&_cond_prodoct,NULL);
11 pthread_cond_init(&_cond_consumer,NULL);
12 }
13 ~Blockqueue(){//析构函数,销毁我们的锁和条件变量
14 pthread_mutex_destroy(&_mutex);
15 pthread_cond_destroy(&_cond_prodoct);
16 pthread_cond_destroy(&_cond_consumer);
17 }
18 //提供公共的接口。出栈和入栈
19 bool QueuePush(int data){
20 //加锁
21 QueueLock();
22 while(QueueIsfull()){//当队列满了生产者等待等待
23 ProductorWait();
24 }
25 //进行入队列的操作
26 _queue.push(data);
27 //唤醒我们的消费者
28 ConsumerWakeup();
29 //解锁
30