用条件变量实现生产者和消费者模型
这个模型实现起来。思路也很简单。首先就是需要定义三个全局变量,一个是互斥锁,一个是条件变量,还有一个就是我们的阻塞队列。
互斥机制的设计
生产消费模型的主要动作就是两个。第一个就是生存者往超市放东西。第二个就是消费者从超市拿东西。我们就以生产者往超市放东西为例,由于超市在这个模型中属于临界资源,也就是说不允许一个生产者和一个消费者同时访问,也不允许多个生产者同时往里边儿放,也不允许多个消费者同时从里边儿拿,在同一个时刻仅允许一个生产者往里面存东西或者是一个消费者从里面拿东西。对于这样的要求,我们就可以引入一把互斥锁,让所有的生产者线程和消费者线程共同竞争一把互斥锁,只有拿到这把互斥锁才能够访问临界资源超市。这种想法反映在代码上就是:push操作和get操作事儿干之前要做的第一件事情都是申请这把锁,事儿干完之后要做的最后一件事情都是释放这把锁
同步机制的设计
然后在这个模型中的同步机制就是只有超市的仓库没有满时,生产者才能往超市里放东西。仓库满了之后,生产者就不能放了。同理只有超市的仓库不为空时,才能允许消费者从超市里拿东西。仓库空了之后消费者就不能拿了
这个机制的实现就是要在之后立即进行一个队列是否为空或者是否为满的判断。如果符合要求,那么就进行我们拿东西或者放东西的操作,如果不符合要求,则调用pthread_cond_wait,进行条件变量的等待。由于这个题目我们等待的时机有两个,一个是队列为空,一个是队列为满。所以我们就分别对这两个时机定义两个条件变量。
生产者执行完操作之后,就调用pthread_cond_signal,唤醒一个因队列为空而陷入等待的消费者,消费者执行完操作之后,就调用pthread_cond_signal,唤醒一个因队列为满而陷入阻塞等待的生产者
一些细节:
本例中定义的锁和条件变量都需要在构造函数中进行初始化,在析构函数中释放
一个因队列为空而陷入阻塞的线程,当其被唤醒时,不一定是队列不为空了,而有可能是某个线程执行了pthread_cond_broadcast,为了确保每个现场被唤醒时都等到了对应的条件变量,所以我们要将原来的if判断语句改成while判断
Put线程并不负责具体商品的生产,它仅仅是负责将生产者生产出的货物放入超市,也就是说真正的生产者将货物生产出来之后通过put的参数将货物交付给put线程。Put真正干的事情就是将这个货物插入到我们的阻塞队列中(之所以叫做阻塞队列,是因为当这个队列为空或者为满时,get或者put线程就要陷入阻塞),同理get也并不负责商品的消费,它仅仅是负责将超市中的货物拿给消费者,在代码中真正干的事情就是从阻塞队列中取出一个货物,然后将它通过get的输出型参数交付给消费者。
代码实现
#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
template <class T>
class BlockQueue{
private:
int cap;
pthread_mutex_t lock;
pthread_cond_t have_space; //生产者
pthread_cond_t have_data; //消费者
std::queue<T> bq;
private:
bool IsFull()
{
return bq.size() == cap ? true : false;
}
bool IsEmpty()
{
return bq.size() == 0 ? true : false;
}
public:
BlockQueue(int _cap):cap(_cap)
{
pthread_mutex_init(&lock, nullptr);
pthread_cond_init(&have_space, nullptr);
pthread_cond_init(&have_data, nullptr);
}
void Put(const T &in) //const type&: 输入型参数
{
//生产的过程
//p_lock;
//lock(&p_lock);
pthread_mutex_lock(&lock);
while(IsFull()){
pthread_cond_wait(&have_space, &lock);
}
bq.push(in);
if(bq.size() >= cap/2){
pthread_cond_signal(&have_data);
}
pthread_mutex_unlock(&lock);
}
void Get(T *out) //Type *: 输出型参数,type &: 输入输出型参数
{
pthread_mutex_lock(&lock);
while(IsEmpty()){
pthread_cond_wait(&have_data, &lock);
}
*out = bq.front();
bq.pop();
pthread_cond_signal(&have_space);
pthread_mutex_unlock(&lock);
}
~BlockQueue()
{
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&have_space);
pthread_cond_destroy(&have_data);
}
};

被折叠的 条评论
为什么被折叠?



