当前位置: 首页 > wzjs >正文

网站开发体会免费全能网站空间

网站开发体会,免费全能网站空间,单一产品企业或多元化产品企业的网站建设与策划有什么不同?,免费电视剧在线观看网站上篇文章:Linux操作系统7- 线程同步与互斥6(POSIX信号量与环形队列生产者消费者模型)-CSDN博客 本篇代码仓库:myLerningCode/l36 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com) 目录 一. 单生产单消费单保…

上篇文章:Linux操作系统7- 线程同步与互斥6(POSIX信号量与环形队列生产者消费者模型)-CSDN博客

本篇代码仓库:myLerningCode/l36 · 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com)

目录

一. 单生产单消费单保存模型

1.1 RingQueue.hpp

1.2 Task.hpp

1.3 MainPC.cpp

1.4 测试

二. 多生产多消费模型        

2.1 分析与代码 

2.2 多生产多消费的意义


一. 单生产单消费单保存模型

        通过RingQueue可以实现生产者消费者之间的协同工作,如果现在想要将消费者的输出结果保存在文件中应该怎么办?

        可以定义两个环形队列,三个线程。让消费者充当第二个队列的生产者。

代码如下:

1.1 RingQueue.hpp

        直接使用上篇文件的代码即可。然后我们需要新增一个类,这个类中包含两个环形队列用于消费者同时访问两个队列

#pragma once
#include <iostream>
#include <vector>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
const int gnum = 10; // 阻塞队列的最大容量template <class T>
class RingQueue
{
private:void P(sem_t &sem){// P操作,申请信号量sem--int n = sem_wait(&sem);if (n < 0)std::cerr << "P操作失败" << std::endl;}void V(sem_t &sem){// V操作,释放信号量,sem++int n = sem_post(&sem);if (n < 0)std::cerr << "V操作失败" << std::endl;}public:RingQueue(const int &maxnum = gnum) : _maxnum(maxnum), _ringQueue(gnum){// 在构造函数中完成信号量的初始化int n = sem_init(&_spaceSem, 0, maxnum);if (n < 0)std::cerr << "spaceSem信号量初始化失败" << std::endl;n = sem_init(&_dataSem, 0, 0);if (n < 0)std::cerr << "dataSem信号量初始化失败" << std::endl;_producerStep = _consumerStep = 0;}~RingQueue(){sem_destroy(&_spaceSem);sem_destroy(&_dataSem);}// 生产者插入数据void push(const T &in){// 申请空间资源P(_spaceSem);// 插入数据_ringQueue[_producerStep++] = in;_producerStep %= _maxnum;// 释放一个数据资源V(_dataSem);}// 消费者获取数据void pop(T *out){// 申请数据资源P(_dataSem);// 插入数据*out = _ringQueue[_consumerStep++];_consumerStep %= _maxnum;// 释放一个空间资源V(_spaceSem);}private:std::vector<T> _ringQueue; // 使用数组来实现环形队列size_t _maxnum;sem_t _spaceSem; // 生产者空间资源信号量sem_t _dataSem;  // 消费者数据资源信号量int _producerStep; // 生产者下标int _consumerStep; // 消费者下标
};

1.2 Task.hpp

        需要新增一个保存者的任务

#pragma once
#include <iostream>
#include <cstdio>
#include <functional>class CalTask
{using func_t = std::function<int(int, int, char)>; // func是一个函数// typedef std::function<int(int,int)> func;
public:CalTask() {}CalTask(int x, int y, char op, func_t func): _x(x), _y(y), _op(op), _callback(func) {}std::string operator()(){int result = _callback(_x, _y, _op);char buffer[1024];snprintf(buffer, sizeof(buffer) - 1, "%d %c %d = %d", _x, _op, _y, result);return buffer;}// 返回任务操作的结果std::string toString(){char buffer[1024];snprintf(buffer, sizeof(buffer) - 1, "%d %c %d = ?", _x, _op, _y);return buffer;}private:int _x;int _y;char _op;         // 操作的任务的idfunc_t _callback; // 调用的函数
};class SaveTask
{typedef std::function<void(const std::string &)> func_t;public:SaveTask() {}SaveTask(const std::string &message, func_t func): _message(message), _callback(func) {}void operator()(){_callback(_message);}private:std::string _message; // 保存的信息func_t _callback;     // 将信息写入文件中
};const std::string oper = "+-*/%";
int my_math(int x, int y, char op)
{int result = 0;switch (op){case '+':result = x + y;break;case '-':result = x - y;break;case '*':result = x * y;break;case '/':{if (y == 0){std::cerr << "div zero" << std::endl;return -1;}else{result = x / y;}break;}case '%':if (y == 0){std::cerr << "moved zero" << std::endl;return -1;}else{result = x % y;}break;default:break;}return result;
}void Save(const std::string &message)
{const std::string task_pwd = "./log.txt";FILE *fp = fopen(task_pwd.c_str(), "a+");if (nullptr == fp){std::cerr << "saver open error" << std::endl;return;}fputs(message.c_str(), fp);fputc('\n', fp);fclose(fp);
}

1.3 MainPC.cpp

#include "RingQueue.hpp"
#include "Task.hpp"
#include <iostream>// 生产者
void *ProductorRoutine(void *args)
{RingQueue<CalTask> *cal_rq = (static_cast<RingQueues<CalTask, SaveTask> *>(args))->_cal_rq;while (true){int x = rand() % 20;int y = rand() % 50;const char op = oper[rand() % oper.size()];CalTask ct(x, y, op, my_math);cal_rq->push(ct);std::cout << "生产者生产任务:" << ct.toString() << " 并传递给消费者完成" << std::endl;}
}// 消费者
void *ConsumerRoutine(void *args)
{RingQueue<CalTask> *cal_rq = (static_cast<RingQueues<CalTask, SaveTask> *>(args))->_cal_rq;RingQueue<SaveTask> *save_rq = (static_cast<RingQueues<CalTask, SaveTask> *>(args))->_save_rq;while (true){CalTask ct;cal_rq->pop(&ct);std::string result = ct();std::cout << "消费者实现任务:" << result << " 实现完成!" << std::endl;SaveTask st(result, Save);save_rq->push(st);std::cout << "消费者传递任务:" << result << " 给保存者完成!" << std::endl;}
}// 保存者
void *SaverRoutine(void *args)
{RingQueue<SaveTask> *save_rq = (static_cast<RingQueues<CalTask, SaveTask> *>(args))->_save_rq;while (true){SaveTask st;save_rq->pop(&st);st();std::cout << "保存者保存任务完成!" << std::endl;}
}void test1()
{RingQueues<CalTask, SaveTask> *rqs = new RingQueues<CalTask, SaveTask>;rqs->_cal_rq = new RingQueue<CalTask>();rqs->_save_rq = new RingQueue<SaveTask>();pthread_t p, c, s;pthread_create(&p, nullptr, ProductorRoutine, rqs);pthread_create(&c, nullptr, ConsumerRoutine, rqs);pthread_create(&s, nullptr, SaverRoutine, rqs);pthread_join(p, nullptr);pthread_join(c, nullptr);pthread_join(s, nullptr);delete rqs;
}int main()
{srand((unsigned int)time(0) ^ getpid() ^ pthread_self());test1();return 0;
}

1.4 测试

        运行结果如下:

二. 多生产多消费模型        

2.1 分析与代码 

        RingQueue环形队列可以保证单个生产者和单个消费者之间的同步与互斥,如果现在有多个生产者和多个消费者的话。如何保证生产者之间的互斥?消费者者之间的互斥?

        阻塞队列中,我们通过加锁的方式让同一时刻只能有一个生产者线程进入临界区或者一个消费者进入临界区。

        而环形队列中, 通过信号量保证了生产者消费者之间的同步与互斥。如果想要保证消费者与消费者之间的互斥,生产者与生产者之间的互斥,也需要加锁保护

        在RingQueue中添加两个成员变量,一个生产者互斥锁,一个消费者互斥锁。同时需要在构造函数中完成锁的初始化,析构函数中完成锁的销毁。

        并且在push函数中加生产者锁,在pop函数中加消费者锁。以实现生产者与生产者之间的互斥和消费者与消费者之间的互斥。(本质是防止多个线程同时访问导致生产者下标或者消费者下标出现数据错误) 

代码如下:

#pragma once
#include <iostream>
#include <vector>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
const int gnum = 10; // 阻塞队列的最大容量template <class T>
class RingQueue
{
private:void P(sem_t &sem){// P操作,申请信号量sem--int n = sem_wait(&sem);if (n < 0)std::cerr << "P操作失败" << std::endl;}void V(sem_t &sem){// V操作,释放信号量,sem++int n = sem_post(&sem);if (n < 0)std::cerr << "V操作失败" << std::endl;}public:RingQueue(const int &maxnum = gnum) : _maxnum(maxnum), _ringQueue(gnum){// 在构造函数中完成信号量的初始化int n = sem_init(&_spaceSem, 0, maxnum);if (n < 0)std::cerr << "spaceSem信号量初始化失败" << std::endl;n = sem_init(&_dataSem, 0, 0);if (n < 0)std::cerr << "dataSem信号量初始化失败" << std::endl;_producerStep = _consumerStep = 0;// 初始化锁pthread_mutex_init(&_pmtx, nullptr);pthread_mutex_init(&_cmtx, nullptr);}~RingQueue(){// 销毁信号量与互斥锁sem_destroy(&_spaceSem);sem_destroy(&_dataSem);//pthread_mutex_destroy(&_cmtx);pthread_mutex_destroy(&_pmtx);}// 生产者插入数据void push(const T &in){// 生产者加锁,保证生产者与生产者之间的互斥pthread_mutex_lock(&_pmtx);// 申请空间资源P(_spaceSem);// 插入数据_ringQueue[_producerStep++] = in;_producerStep %= _maxnum;// 释放一个数据资源V(_dataSem);// 解锁pthread_mutex_unlock(&_pmtx);}// 消费者获取数据void pop(T *out){// 消费者加锁pthread_mutex_lock(&_cmtx);// 申请数据资源P(_dataSem);// 插入数据*out = _ringQueue[_consumerStep++];_consumerStep %= _maxnum;// 释放一个空间资源V(_spaceSem);// 解锁pthread_mutex_unlock(&_cmtx);}private:std::vector<T> _ringQueue; // 使用数组来实现环形队列size_t _maxnum;sem_t _spaceSem; // 生产者空间资源信号量sem_t _dataSem;  // 消费者数据资源信号量int _producerStep; // 生产者下标int _consumerStep; // 消费者下标pthread_mutex_t _pmtx;pthread_mutex_t _cmtx;
};

MainPC.cpp

#include <iostream>
#include <memory>
#include <string>#include <unistd.h>
#include <pthread.h>
#include "RingQueue.hpp"
#include "Task.hpp"const std::string OP = "+-*/%";
void *producer(void *args)
{// 获取交易场所 - 阻塞队列RingQueue<CalTask> *rq = static_cast<RingQueue<CalTask> *>(args);while (true){int x = rand() % 100;int y = rand() % 100;char op = OP[rand() % OP.size()];// 打印日志printf("生产者生产的数据:%d %c %d 并交给消费者计算\n", x, op, y);CalTask ct(x, y, op, my_math);rq->push(ct);}return nullptr;
}void *consumer(void *args)
{// 获取交易场所 - 生产消费阻塞队列,消费保存阻塞队列RingQueue<CalTask> *rq = static_cast<RingQueue<CalTask> *>(args);while (true){// 获取任务计算CalTask ct;rq->pop(&ct);std::string result = ct();std::cout << "消费者获取数据并计算:" << result << std::endl;}return nullptr;
}int main()
{srand((unsigned int)time(0) ^ getpid());// 建立任务队列和保存队列RingQueue<CalTask> *rq = new RingQueue<CalTask>;pthread_t c[3], p[3];pthread_create(&c[0], nullptr, consumer, (void *)rq);pthread_create(&c[1], nullptr, consumer, (void *)rq);pthread_create(&c[2], nullptr, consumer, (void *)rq);pthread_create(&p[0], nullptr, producer, (void *)rq);pthread_create(&p[1], nullptr, producer, (void *)rq);pthread_create(&p[2], nullptr, producer, (void *)rq);pthread_join(c[0], nullptr);pthread_join(c[1], nullptr);pthread_join(c[2], nullptr);pthread_join(p[0], nullptr);pthread_join(p[1], nullptr);pthread_join(p[2], nullptr);delete rq;return 0;
}

测试结果如下:

可以看到,长时间没有出错

如果将加锁解锁操作进行注释:

会出现段错误,因为访问了非法内存

2.2 优化加解锁

        我们申请信号量和释放信号量是原子操作,不需要加锁解锁。无需将这个两个代码放入到临界区。并且一个线程在加锁期间,其他线程是可以申请信号量的!

    // 生产者插入数据void push(const T &in){// 申请空间资源P(_spaceSem);// 生产者加锁,保证生产者与生产者之间的互斥pthread_mutex_lock(&_pmtx);// 插入数据_ringQueue[_producerStep++] = in;_producerStep %= _maxnum;// 解锁pthread_mutex_unlock(&_pmtx);// 释放一个数据资源V(_dataSem);}// 消费者获取数据void pop(T *out){// 申请数据资源P(_dataSem);// 消费者加锁pthread_mutex_lock(&_cmtx);// 插入数据*out = _ringQueue[_consumerStep++];_consumerStep %= _maxnum;// 解锁pthread_mutex_unlock(&_cmtx);// 释放一个空间资源V(_spaceSem);}

        一样一来,一个线程加锁进入临界区之后不会去影响其他线程申请信号量。从而提高整体的效率。 

2.3 多生产多消费的意义

        与阻塞队列BlockQueue一样,多生产多消费的时候。生产线程生产数据可能需要很多时间,一个生产者生产者访问环形队列的时候不妨碍其他线程生产自己的资源。一个消费者访问环形队列拿数据的时候不妨碍其他消费者拿到数据进行处理


文章转载自:

http://sYcU8Z5U.bzsqr.cn
http://ENmCmcwe.bzsqr.cn
http://BQrrKCNo.bzsqr.cn
http://5Id9XeuQ.bzsqr.cn
http://6D3s6JzC.bzsqr.cn
http://QSzwbHug.bzsqr.cn
http://UVgEXmZw.bzsqr.cn
http://lPGbWnDy.bzsqr.cn
http://DWhPxRCn.bzsqr.cn
http://vyjItcYr.bzsqr.cn
http://xzWAUZeU.bzsqr.cn
http://MktOEgal.bzsqr.cn
http://SyLS8IRW.bzsqr.cn
http://CwyyKflQ.bzsqr.cn
http://OjAV2XAD.bzsqr.cn
http://TuCtNZyx.bzsqr.cn
http://buCTDLUo.bzsqr.cn
http://CIKrXF8z.bzsqr.cn
http://d8X0IYzI.bzsqr.cn
http://OoL7mMhV.bzsqr.cn
http://x9TmZzHo.bzsqr.cn
http://Brs0m93Q.bzsqr.cn
http://O9p3rjBZ.bzsqr.cn
http://RxzUoSVy.bzsqr.cn
http://6PuI0BCb.bzsqr.cn
http://xynCJuY6.bzsqr.cn
http://sUnpyFaQ.bzsqr.cn
http://rTj6ivLL.bzsqr.cn
http://p8W9pqDs.bzsqr.cn
http://WA7FErw6.bzsqr.cn
http://www.dtcms.com/wzjs/738154.html

相关文章:

  • 可以直接进入网站的正能量照片公司建设网站需要去哪报备
  • 哪些做直播卖食品的网站软文营销的技巧有哪些?
  • 高端网站制作网站设计做网站一定要psd吗
  • 楚天网站建设合同自贡市城市建设投资开发集团有限公司网站
  • 长春市快速建站网站网络电话免费版
  • 佛山外贸网站建设资讯丰台网站建设公司
  • 集团酒店网站建设制作网站能挣钱
  • 住建部工程建设标准网站电脑网站 源码
  • asp做购物网站app制作平台推荐
  • 个人网站用wordpress吗推荐一些做电子的网站
  • 网站页面如何设计图今天天津最新通告
  • 网站开发技术孵化网页一键生成小程序
  • 做网站挣钱快又多爱站工具包的模块
  • 南阳集团网站建设网站开发 网页设计北京师范大学出版社
  • 做一个网站多久子目录安装wordpress
  • 微信上建微网站要钱吗wordpress 仿头条主题
  • 广州市海珠区建设局网站网站制作流程一般制作流程?
  • 毕业设计做网站应该学什么贵阳网站建设多钱钱
  • 海南做网站的技术公司个人网站模板h5
  • 做数字艺术设计的网站企业网站首页效果图设计与制作
  • 做网站编辑要会什么陕西网站建设咨询
  • 网站托管 建设方案成都建设网站的公司有哪些
  • 比较好的h5网站新乐市建设银行网站
  • 青海省建设厅报名网站成都装修建材网站建设
  • 扁平化网站模板专业网站定制团队
  • 泸州建设厅官方网站面料做电商 哪个网站好
  • 当涂县微网站开发免费网站的资源可以发公众号吗
  • 装修的网站信息网站 cms
  • 云南专业网站建站建设姜堰区住房和城乡建设局网站
  • 视频网站怎么建产品销售型企业网站