目录
那么我们说了有三种关系,那么我们需要几把锁呢?几个条件变量呢?
什么是生产者与消费者模型
工厂:勤劳的生产者
街角的工厂里,机器日夜运转,工人们忙碌不停。他们生产着各种各样的商品,比如面包、饮料、日用品等。工厂的任务就是不停地制造这些商品,保证供应充足。
超市:中间的缓冲仓库
工厂生产出来的商品并不会直接送到居民手中,而是先运到街对面的超市。超市就像一个巨大的仓库,暂时存放着这些商品。它调节着工厂的生产节奏和居民的消费速度,防止工厂生产的商品堆积如山,也避免居民想买东西时却无货可买。
普通居民:热情的消费者
街上的居民们每天都有各种各样的需求,需要购买超市里的商品来满足生活。他们有的是上班族,下班后匆匆赶来买晚餐的食材;有的是家庭主妇,精心挑选着孩子的零食和生活用品。
剧情上演
第一幕:工厂的忙碌与超市的充实
清晨,工厂里就开始了一天的忙碌。工人们将一批批新鲜出炉的面包、香甜的饮料和各种日用品打包装箱。然后,这些商品被运送到超市。超市的员工们迅速将货物上架,摆放整齐,准备迎接顾客的到来。
此时,工厂就像一个不知疲倦的生产者,源源不断地制造商品;超市则是一个缓冲区,暂时存储着这些商品,等待消费者前来购买。
第二幕:消费者的热情与超市的热闹
随着太阳升高,居民们纷纷走出家门,来到超市购物。他们推着购物车,在货架间穿梭,挑选着自己需要的商品。有的居民在面包区挑选新鲜的面包,有的在饮料区挑选自己喜欢的饮品,还有的在日用品区挑选洗发水、牙膏等。
超市里人来人往,热闹非凡。居民们就像热情的消费者,不断地从超市这个“缓冲区”中取走商品,满足自己的生活需求。
第三幕:供需的平衡与协调
然而,有时候也会出现一些小状况。比如,工厂生产速度过快,而居民消费速度较慢,导致超市的库存积压。这时,工厂可能会接到超市的通知,暂时减缓生产速度,等库存减少后再恢复正常生产。
又或者,居民们突然对某种商品需求大增,而工厂的生产速度跟不上,导致超市该商品缺货。这时,超市会紧急通知工厂加快生产,同时可能会采取一些限购措施,保证每个居民都能买到一些。
在这个过程中,工厂、超市和居民之间不断地进行着信息交流和协调,就像生产者与消费者模型中的同步机制,确保整个系统的稳定运行。
生活中的启示
这个“生活剧”其实就是生产者与消费者模型的一个生动演绎。工厂对应生产者,居民对应消费者,而超市则相当于两者之间的缓冲区。通过这个模型,我们可以更好地理解生活中的许多场景,比如工厂与商场的货物供应、餐厅厨房与顾客的餐食提供等。它帮助我们优化资源配置,提高效率,让我们的生活更加有序和便捷
提炼:
1.共享或者临界资源
2.我们要研究生产消费模型,就需要研究清楚多个生产,多个消费的同步互斥关系!!!
生产者和生产者:互斥
消费者和消费者:互斥
生产者和消费者:互斥&&同步关系
总结:
3 种关系
2.种角色 -- 生产者和消费者
1 个交易场所
线程池--代码中的运用
(一)线程池是什么
线程池是一组预先创建并可重复使用的线程集合。它就像超市里的一支“员工团队”,这些员工平时处于待命状态,当有任务(比如搬运货物、整理货架、帮助顾客等)时,主管(相当于程序中的任务分配者)就会指派空闲的员工去完成,而不是每次有任务都临时招聘新员工。
(二)为什么需要线程池
频繁地创建和销毁线程会消耗系统资源,就像每次有任务都临时招聘员工一样,招聘、培训、解雇的过程都需要时间和成本。而线程池可以复用已有的线程,提高效率,就像超市有一支稳定的员工团队,可以快速响应各种任务,无需每次都走招聘流程。
引入锁和条件变量
比如生产者工厂在往超市进货的时候,在货架上放了一个面包,这时候消费者把这个面包拿走了。这是可以的嘛?我们超市知不知道呢;
答案是不知道的,所以我们放面包和拿面包的时候不能同时运行,这个时候我们就需要锁了。
那么在超市与消费者之间,当消费者想要一个面包的时候,超市这个时候没有,然后消费者回到了家里面,他又在想这个时候超市上面包没有,然后他又回到超市去看,结果超市还是没有上面包,然后消费者就会白白跑。这个时候我们就可以引入条件变量,由超市告诉消费者。有没有资源?
那么我们说了有三种关系,那么我们需要几把锁呢?几个条件变量呢?
生产者和生产者:互斥
消费者和消费者:互斥
生产者和消费者:互斥&&同步关系
答案是一把锁,俩个条件变量。
在消费者中,如果没有资源,消费者会阻塞在条件变量中,每有一个资源就会放出一个消费者,那么消费者之间只需要竞争自己的条件变量就可以了。
那么在生产者中也同理,生产者竞争自己的条件变量。
但是生产者和消费者看见的是同一份资源,就是一个临界资源,我们就要对这个临界资源上锁,让放出来的生产者和消费者去竞争这一把锁。
一份基本的基于阻塞队列的生产者消费者模型代码
Block_queue.hpp
#pragma once
#include <iostream>
#include<queue>
#include <unistd.h>
#include <pthread.h>
using namespace std;
static int nnn = 1;
namespace xjh
{
const int num = 10;
template<typename T>
class block_queue
{
public:
block_queue(int cap,pthread_cond_t* conp,pthread_cond_t* conc,pthread_mutex_t* mutex)
:_cap(cap)
,_condP(conp)
,_condC(conc)
,_mutex(mutex)
{
pthread_cond_init(_condP, nullptr);
pthread_cond_init(_condC, nullptr);
pthread_mutex_init(_mutex, nullptr);
}
void Push()
{
//sleep(1);
pthread_mutex_lock(_mutex);
while(_q.size() == _cap)
{
pthread_cond_wait(_condP,_mutex);
cout<<"生产者等待"<<endl;
}
_q.push(nnn);
cout<<"生产完毕唤醒消费者 "<<nnn<<endl;
nnn++;
pthread_cond_signal(_condC);
pthread_mutex_unlock(_mutex);
}
void Pop()
{
sleep(1);
int tmp = 0;
pthread_mutex_lock(_mutex);
while(_q.size() == 0)
{
pthread_cond_wait(_condC,_mutex);
cout<<"消费者等待"<<endl;
}
tmp = _q.front();
_q.pop();
cout<<"消费完毕唤醒生产者 "<<tmp<<endl;
pthread_cond_signal(_condP);
pthread_mutex_unlock(_mutex);
}
~block_queue()
{
}
private:
queue<T> _q;
int _cap;
pthread_cond_t* _condP;
pthread_cond_t* _condC;
pthread_mutex_t* _mutex;
};
}
main.cc
#pragma once
#include <iostream>
#include<queue>
#include <unistd.h>
#include <pthread.h>
using namespace std;
static int nnn = 1;
namespace xjh
{
const int num = 10;
template<typename T>
class block_queue
{
public:
block_queue(int cap,pthread_cond_t* conp,pthread_cond_t* conc,pthread_mutex_t* mutex)
:_cap(cap)
,_condP(conp)
,_condC(conc)
,_mutex(mutex)
{
pthread_cond_init(_condP, nullptr);
pthread_cond_init(_condC, nullptr);
pthread_mutex_init(_mutex, nullptr);
}
void Push()
{
//sleep(1);
pthread_mutex_lock(_mutex);
while(_q.size() == _cap)
{
pthread_cond_wait(_condP,_mutex);
cout<<"生产者等待"<<endl;
}
_q.push(nnn);
cout<<"生产完毕唤醒消费者 "<<nnn<<endl;
nnn++;
pthread_cond_signal(_condC);
pthread_mutex_unlock(_mutex);
}
void Pop()
{
sleep(1);
int tmp = 0;
pthread_mutex_lock(_mutex);
while(_q.size() == 0)
{
pthread_cond_wait(_condC,_mutex);
cout<<"消费者等待"<<endl;
}
tmp = _q.front();
_q.pop();
cout<<"消费完毕唤醒生产者 "<<tmp<<endl;
pthread_cond_signal(_condP);
pthread_mutex_unlock(_mutex);
}
~block_queue()
{
}
private:
queue<T> _q;
int _cap;
pthread_cond_t* _condP;
pthread_cond_t* _condC;
pthread_mutex_t* _mutex;
};
}