引言
一、实现一个网关来过滤流经网关的数据
二、农忙时节收割麦子
生产者与消费者模型
模型实现
完整源码:
引言
阐述这个模型之前先引入俩个例子:
一、实现一个网关来过滤流经网关的数据
网关会捕捉大量的数据然后进行分析处理,之后再把我们分析处理后的数据送至磁盘中,来进行存储,不过在这一过程中,流经网关的信息量非常巨大,如果数据不能及时进行处理就会被丢弃(俗称丢包),那如何来进行实现呢?
我们在学习了多线程之后,知道了可以利用多线程来提高cpu的处理效率,用到这里的话也是特别符合条件
但是即使是使用了多线程的思想处理了这个问题,还是会存在一些数据丢包的情况,因为在数据存入磁盘这一过程是特别的低效,一种极端的情况,我所有的分析处理线程都卡在了等待磁盘存入这一步,一大堆线程看着数据慢悠悠的送往磁盘。然后新产生的数据就会因为无法捕捉导致数据丢失。
二、农忙时节收割麦子
父亲叫来了一个收割机在地里收麦子,麦子需要被装入一个蛇皮袋子里然后搬运到车上(不能放地上),所以父亲只能不断的执行灌袋、装车这俩个动作,可是就算父亲动作再利落,收割机源源不断收取的麦子还是会在父亲装车的时候掉落在地上,那么采取多线程思想,父亲叫儿子过来帮忙,于是父亲和儿子一起执行灌袋、装车的动作,父子俩的配合非常紧密,可还是会有麦子掉到了地上。
那么如何解决这种问题呢?
如果父亲和儿子一个人只负责灌袋、一个人只负责装车,那么掉在地上的麦子就会更少一些。
生产者与消费者模型
在大量的数据处理任务的产生时:
采用单执行流的缺陷:
1、效率低下
2、资源利用不一定合理
3、耦合度比较强
如果一个线程处出现问题,必须要对整个线程体系进行检查
解决思想:
将任务的产生与处理分离开来,通过一个任务队列来进行交互
这个任务队列就相当于儿子将麦子装满然后直接放在地上,剩下的装车任务交给父亲来做即可。
在网关的例子中也是使用一个任务队列来进行保存网关接收到的信息,网关不断的接收数据交给各个线程,各个线程取出数据来进行分析,分析结果放入任务队列中,磁盘在进行不断的存储。
就是这样一个 ① 生产与消费动作解耦合
② 支持忙闲不均
③ 支持并发
模型实现
生产者与生产者的关系: 互斥(一个生产完了,才能轮到下一个生产)
消费者与消费者的关系: 互斥(一个消费完了,才能轮到下一个消费)
生产者与消费者的关系:同步 + 互斥
(满了就不能放,空了就不能取)条件控制为了访问资源的合理性
(生产者生产出来了,消费者才能进行消费)资源的唯一访问
实现一个线程安全的阻塞队列,接下来创建多个线程入队数据,多个线程出队数据
完成类中构造与析构函数
#include<iostream>
#include<pthread.h>
#include<queue>
template<class T>
class BlockQueue
{
private:
std::queue<T> _q;
int _capacity;
pthread_mutex_t _mutex;
pthread_cond_t _cond_pro;
pthread_cond_t _cond_con;
public:
BlockQueue(int capacity)
: _capacity(capacity)
{
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_cond_pro, NULL);
pthread_cond_init(&_cond_con, NULL);
}
~BlockQueue()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond_pro);
pthread_cond_destroy(&_cond_con);
}
bool Push(const T& data);
bool Pop(T* data);
}
完成类中入队出队操作
bool Push(const T& data)
{
pthread_mutex_lock(&_mutex); // 1、加锁
while(_capacity == _q.size()) // 2、当队列中元素满了,进行等待阻塞
{
pthread_cond_wait(&_cond_pro, &_mutex);
}
_q.push(data); // 3、入队数据
pthread_cond_signal(&_cond_con); // 4、唤醒消费者
pthread_mutex_unlock(&_mutex); // 5、解锁
}
bool Pop(T* data)
{
pthread_mutex_lock(&_mutex); // 1、加锁
while(_q.size() == 0){ // 2、如果队列为空,无法进行读取 则阻塞
pthread_cond_wait(&_cond_con, &_mutex);
}
*data = _q.front(); // 3、获取数据
_q.pop(); // 4、记得要pop出队
pthread_cond_signal(&_cond_pro); // 5、唤醒生产者
pthread_mutex_unlock(&_mutex); // 6、解锁
}
完成main函数中实现四个线程作为生产者、四个线程作为消费者
#define MAX_SIZE 4
int main()
{
BlockQueue<int> q;
pthread_t pro_tid[MAX_SIZE], con_tid[MAX_SIZE];
int ret;
for(int i = 0; i < MAX_SIZE; i++)
{
ret = pthread_create(&pro_tid[i], NULL, productor, (void*)&q);
if(ret != 0){
std::cout<<"create error"<<std::endl;
return -1;
}
ret = pthread_create(&con_tid[i], NULL, consumer, (void*)&q);
if(ret != 0){
std::cout<<"create error"<<std::endl;
return -1;
}
}
for(int i = 0; i < MAX_SIZE; i++)
{
pthread_join(pro_tid[i], NULL);
pthread_join(con_tid[i], NULL);
}
return 0;
}
完成生产者与消费者的入口函数书写
void *productor(void *arg)
{
BlockQueue<int> *q = (BlockQueue<int>*)arg;
int data = 0;
while(1)
{
q->Push(data);
printf("+++++%p: Push data :%d\n", pthread_self(), data++);
}
return NULL;
}
void *consumer(void *arg)
{
BlockQueue<int> *q = (BlockQueue<int>*)arg;
while(1)
{
int data;
q->Pop(&data);
printf("------%p: Push data :%d\n", pthread_self(), data);
}
return NULL;
}
完整源码:
#include<iostream>
#include<pthread.h>
#include<queue>
#include<stdio.h>
#define MAX_CAPACITY 5
template<class T>
class BlockQueue
{
private:
std::queue<T> _q;
int _capacity;
pthread_mutex_t _mutex;
pthread_cond_t _cond_pro;
pthread_cond_t _cond_con;
public:
BlockQueue(int capacity = MAX_CAPACITY)
: _capacity(capacity)
{
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_cond_pro, NULL);
pthread_cond_init(&_cond_con, NULL);
}
~BlockQueue()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond_pro);
pthread_cond_destroy(&_cond_con);
}
bool Push(const T& data)
{
pthread_mutex_lock(&_mutex); // 1、加锁
while(_capacity == _q.size()) // 2、当队列中元素满了,进行等待阻塞
{
pthread_cond_wait(&_cond_pro, &_mutex);
}
_q.push(data); // 3、入队数据
pthread_cond_signal(&_cond_con); // 4、唤醒消费者
pthread_mutex_unlock(&_mutex); // 5、解锁
}
bool Pop(T* data)
{
pthread_mutex_lock(&_mutex); // 1、加锁
while(_q.size() == 0){ // 2、如果队列为空,无法进行读取 则阻塞
pthread_cond_wait(&_cond_con, &_mutex);
}
*data = _q.front(); // 3、获取数据
_q.pop(); // 4、记得要pop出队
pthread_cond_signal(&_cond_pro); // 5、唤醒生产者
pthread_mutex_unlock(&_mutex); // 6、解锁
}
};
void *productor(void *arg)
{
BlockQueue<int> *q = (BlockQueue<int>*)arg;
int data = 0;
while(1)
{
q->Push(data);
printf("+++++%p: Push data :%d\n", pthread_self(), data++);
}
return NULL;
}
void *consumer(void *arg)
{
BlockQueue<int> *q = (BlockQueue<int>*)arg;
while(1)
{
int data;
q->Pop(&data);
printf("------%p: Push data :%d\n", pthread_self(), data);
}
return NULL;
}
#define MAX_SIZE 4
int main()
{
BlockQueue<int> q;
pthread_t pro_tid[MAX_SIZE], con_tid[MAX_SIZE];
int ret;
for(int i = 0; i < MAX_SIZE; i++)
{
ret = pthread_create(&pro_tid[i], NULL, productor, (void*)&q);
if(ret != 0){
std::cout<<"create error"<<std::endl;
return -1;
}
ret = pthread_create(&con_tid[i], NULL, consumer, (void*)&q);
if(ret != 0){
std::cout<<"create error"<<std::endl;
return -1;
}
}
for(int i = 0; i < MAX_SIZE; i++)
{
pthread_join(pro_tid[i], NULL);
pthread_join(con_tid[i], NULL);
}
return 0;
}
底行模式下替换命令:
: 22,26s/hello/hi/g 将22行到26行中的hello替换为hi
:14,34s/abcdef//g 将14行到34行中的abcdef替换为(空)(即为删除)
:noh 去掉高亮显示