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

手机能建网站不百度灰色词排名代发

手机能建网站不,百度灰色词排名代发,做网站的规范尺寸,贵州省城乡和住房建设厅网站目录 一、进程间通信的理解 1.为什么进程间要通信 2.如何进行通信 二、匿名管道 1.管道的理解 2.匿名管道的使用 3.管道的五种特性 4.管道的四种通信情况 5.管道缓冲区容量 三、进程池 1.进程池的理解 2.进程池的制作 四、源码 1.ProcessPool.hpp 2.Task.hpp 3…

目录

一、进程间通信的理解

1.为什么进程间要通信

2.如何进行通信

二、匿名管道

1.管道的理解

2.匿名管道的使用

3.管道的五种特性

4.管道的四种通信情况

5.管道缓冲区容量

三、进程池

1.进程池的理解

2.进程池的制作

四、源码 

1.ProcessPool.hpp

2.Task.hpp

3.test.cc


        本文旨在分享我对管道技术的理解和见解。由于个人知识和经验的限制,文中可能存在错误或遗漏。我真诚地邀请各位读者在阅读过程中发现任何问题时,指出错误并提供宝贵的意见。您的反馈将是我不断进步和完善的重要动力。

一、进程间通信的理解

1.为什么进程间要通信

        首先进程之间是相互独立的,尽管是父子进程之间,它们虽然资源共享,但当子进程需要修改数据时仍然需要进行写时拷贝,保持独立性。

        而让进程间通信可以实现数据之间的交互资源共享事件通知,又或者是让一个进程对另一个进程进行控制

        进程间通信是操作系统中实现进程间协作和数据交换的重要机制,它使得多个进程能够共同完成任务,提高系统的效率和可靠性。

2.如何进行通信

        进程间通信的原理其实很简单,只需要两个进程共同访问一个资源,而一个进程对资源的更改能被另一进程感知到,从而做出相应的操作。

        所以通信的前提是进程之间能够访问同一个资源,而且该资源是公共的,而不是某进程内部的。

二、匿名管道

1.管道的理解

        我们把进程之间通信的介质(资源)叫作管道。开发者在设计管道技术时文件系统已经比较成熟,所以为了方便管理该资源就使用文件来实现,而对文件的读写就是通信的过程,但它与一般的文件还是有些区别,文件都是储存到磁盘上的,而进程之间通信用的文件并不需要把它储存到磁盘上,它只是作为一个传输介质。

        它比较特殊,所以起名为管道。管道其实是一个内存级的文件

        注意:父子进程之间的管道叫作匿名管道,顾名思义就是没有名字,也不需要名字,因为子进程能够继承下来父进程开辟的管道资源。 

2.匿名管道的使用

创建匿名管道常用的接口是:

                int pipe(int pipefd[2]);

需要包含头文件:

                #include<unistd.h>

  • 返回值:创建成功返回0,失败返回-1
  • 参数:这个是一个输出型参数,传入一个int类型长度为2的数组,然后得到pipefd[0]:以读的方式打开的文件描述符pipefd[1]:以写的方式打开的文件描述符

示例:

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
int main()
{int pipefd[2];pipe(pipefd);int rfd = pipefd[0],wfd = pipefd[1];pid_t id = fork();if(id == 0){close(wfd);//关闭子进程的写文件,只让它读int k=0;while(true){read(rfd,&k,sizeof(k));printf("read:%d\n",k);}}else{close(rfd);//关闭父进程的读文件,只让它写。int num=0;while(true){write(wfd,&num,sizeof(num));num++;sleep(1);}}return 0;
}

        因为只是一个小测试,代码写的并不严谨(没有检查调用是否成功,没有关闭文件,没有进程等待)大家不用太在意,能说明问题就行。

        要记住pipefd[2]中哪个是读哪个是写有一个小技巧,0像嘴巴,所以下标为0的是读,1像钢笔,所以1下标是写。

3.管道的五种特性

  1. 匿名管道,只能用来进行具有血缘关系的进程间通信(用于父与子)。
  2. 管道文件,自带同步机制。如上代码示例,父进程写一次休眠一秒,而子进程是一直不断地读,快的一端会迁就于慢的一端,最后实现同步。
  3. 管道是面向字节流的。怎么读与怎么写并没有联系,比如写入“hello world”,但可能读到“hel”,这取决于你要读多少字节。
  4. 管道是单向通信的。也就是a(表示进程)写的时候b读。b写的时候a在读。而不是既在写同时也在读。
  5. 管道(文件)的生命周期是随进程的。进程结束管道也随之销毁。

4.管道的四种通信情况

  1. 写慢,读快 --- 读端就要阻塞(等待写端写入)。
  2. 写快,读慢 --- 到管道容量满了后,写端就要阻塞(等待读端读取数据,然后就可以覆盖式地继续往管道写入)。
  3. 写关闭,读继续 --- read就会返回0,表示文件结尾。
  4. 写继续,读关闭 --- 写端不再有意义,系统会杀掉写端进程。

5.管道缓冲区容量

        管道缓冲区容量为64kb,大家可以根据管道的性质与通信特点,自行进行测试,我这里就不再展示。

三、进程池

1.进程池的理解

        在程序使用内存的时候,比如vector扩容机制,会提前给你开辟一块空间供你使用,尽管现在用不到,相当于做一下预备。减少开辟空间的频次,从而达到提高效率的效果。

        那么进程池也同样,给父进程提前开辟一些子进程,提供父进程使用。其中我们使用匿名管道建立联系。

        在父进程给子进程派发任务时,为了提高效率会让每个子进程均匀地分配到任务(称为负载均匀),而不是把大部分的任务都派发到一个子进程上,通常会有以下策略:

  • 轮询:按顺序一一分配。
  • 随机:随机进行分配。
  • 负载因子:设计一个负载因子,让子进程按负载因子的大小排成一个小根堆,每次取出堆头的子进程派发任务,然后更新负载因子插回到堆中。

2.进程池的制作

        在面向对象的编程中最重要的就是对对象的描述与组织,这里我们的核心就是对管道进行管理。那么首先需要一个类对管道进行描述。

class Channel
{
public:Channel(int wfd, int id) : _wfd(wfd), _id(id){}//... ...~Channel(){}
private:int _wfd;int _id;
};

_wfd是该管道对应写端的fd,_id是该管道对应的子进程的pid。 

        这里我们不必把rfd(读端fd)加入,因为我们现在对管道的描述组织,目的是方便父进程管理,而rfd是给子进程用的,所以不用添加为变量。

        这里我们就以轮询的方式派发任务,刚才创建的Channel相当于对管道的描述,接下来创建ChannelManage进行组织。这里选择使用数组来管理,派发任务方式选择轮询,所以需要记录下一个需要派发到的管道的下标。

class ChannelManage
{
public:ChannelManage():_next(0){}//... ...~ChannelManage(){}
private:vector<Channel> _channels;int _next;
};

接下来还需要创建一个类对整体的进程池做管理。

class ProcessPool
{
public:ProcessPool(int num) : _n(num){}// ... ...~ProcessPool(){}
private:ChannelManage _cm;int _n;
};

其中_n表示需要创建多少子进程,这是由使用者来决定的。

在ProcessPool中我们准备实现这些方法

  • void Create():用于创建子进程。

        由于我们是要生成多个通道所以需要循环来进行,而单趟循环需要做以下这些操作:

        1.创建管道,然后创建子进程。(这样能让子进程继承到管道信息)

        2.关于子进程:写端关闭,然后执行Work(),最后把读端关闭,并exit退出。

        3.关于父进程:读端关闭,然后把wfd,pid存入_cm中。

  • void Work(int  rfd):用于子进程读取任务码并执行命令。
  • void Run():用于获取派发任务。
  • void Stop():用于关闭写端回收子进程

最后为方便测试我们还需要一个管理任务的类和方法。我们可以单独创建一个Task.hpp文件。

class TaskManage
{
public:TaskManage(){   //随机数种子srand((unsigned int)time(nullptr));}int GetCode(){   //随机生成任务码(数组下标)return rand()%_tasks.size();}void ExeTask(int code){   //执行任务_tasks[code]();}// ... ...~TaskManage(){}
private:vector<function<void()>> _tasks;//用于储存任务的数组
};

        然后需要在ProcessPool中放入TaskManage成员变量,并在ProcessPool的构造函数中完成对_tasks中内容的插入。具体操作参考下面源码。

四、源码 

1.ProcessPool.hpp

#pragma once
#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <sys/wait.h>
#include <vector>
#include "Task.hpp"
#define NUM 5
using namespace std;
class Channel
{
public:Channel(int wfd, int id) : _wfd(wfd), _id(id){}void Write(int code){write(_wfd,&code,sizeof(code));}void Close(){close(_wfd);}void WaitPid(){waitpid(_id,nullptr,0);cout<<"等待进程"<<_id<<"成功"<<endl;}~Channel(){}private:int _wfd;int _id;
};
class ChannelManage
{
public:ChannelManage():_next(0){}void Insert(int wfd, int id){_channels.emplace_back(wfd, id);}int GetChannel()//轮询访问子进程{int tmp = _next;_next++;_next %= _channels.size();return tmp;}void WriteManage(int code,int index){_channels[index].Write(code);}void Close(){for(int i=0;i<_channels.size();i++){_channels[i].Close();}}void WaitPid(){for(int i=0;i<_channels.size();i++){_channels[i].WaitPid();}}~ChannelManage(){}
private:vector<Channel> _channels;int _next;
};class ProcessPool
{
public:ProcessPool(int num) : _n(num){_tm.InsertTask(PrintLog);_tm.InsertTask(Download);_tm.InsertTask(Upload);}void Work(int rfd){while (true){int code;ssize_t n = read(rfd, &code, sizeof(code));if (n > 0){if(n != sizeof(code)) continue;else{//执行任务_tm.ExeTask(code);}}else{cout<<"子进程"<<getpid()<<"退出"<<endl;break;}}}void Create(){for (int i = 0; i < _n; i++){int pipefd[2];pipe(pipefd);pid_t id = fork();if (id == 0){close(pipefd[1]);Work(pipefd[0]);close(pipefd[0]);exit(0);}else{close(pipefd[0]);_cm.Insert(pipefd[1], id);}}}void Run(){int ChannelCode = _cm.GetChannel();int TaskCode = _tm.GetCode();_cm.WriteManage(TaskCode,ChannelCode);}void Stop(){_cm.Close();_cm.WaitPid();}~ProcessPool(){}
private:ChannelManage _cm;int _n;TaskManage _tm;
};

2.Task.hpp

#pragma once
#include <iostream>
#include <vector>
#include <functional>
#include <ctime>
#include <cstdlib>
using namespace std;
void PrintLog()
{std::cout << "我是一个打印日志的任务" << std::endl;
}void Download()
{std::cout << "我是一个下载的任务" << std::endl;
}void Upload()
{std::cout << "我是一个上传的任务" << std::endl;
}
class TaskManage
{
public:TaskManage(){srand((unsigned int)time(nullptr));}void InsertTask(void(*fun)()){_tasks.push_back(fun);}int GetCode(){return rand()%_tasks.size();}void ExeTask(int code){_tasks[code]();}~TaskManage(){}
private:vector<function<void()>> _tasks;
};

3.test.cc

#include "ProcessPool.hpp"
int main()
{ProcessPool pp(NUM);pp.Create();int k = 10;while(k--){pp.Run();}pp.Stop();return 0;
}

http://www.ritt.cn/news/26489.html

相关文章:

  • wordpress 商业网站5188关键词平台
  • 杭州网站建设设计公司网站底部友情链接
  • 宝安做棋牌网站建设哪家服务好今天新闻头条
  • 古风自己做头像的网站佛山网站设计实力乐云seo
  • 广西灵山县建设局网站在线识别图片来源
  • 黑客网站免费盗号百度品牌广告多少钱一个月
  • 做网站_接活百度广告投放代理商
  • 好的网站建设公司微博搜索引擎优化
  • 网站推广的方法枫子网站交易网
  • 长沙网页制作网站seo推广专员工作好做吗
  • php网站后台建设沈阳今天刚刚发生的新闻
  • 有代源码怎么做自己网站淘宝网店代运营正规公司
  • 网站 公众号 建设方案高端网站建设南宁
  • 做画册好的国外网站推荐非企户百度推广
  • 怎么做付款下载网站百度站内搜索代码
  • 高级网站开发工程师证书企业网络推广方案
  • 常德网站建设哪家快郑州seo优化外包公司
  • 如何开发cms网站全国疫情高峰感染进度
  • 网站后台文章添加成功 不显示广告sem是什么意思
  • 网站建设数据保存在哪儿百度电脑网页版
  • 哪个网站有学做内帐的视频百度开发平台
  • 如何写一个可以做报价计算的网站怎么在网上做推广
  • 网页设计图片滚动代码怎么弄杭州网站推广优化
  • 成都网站建设哪家万网域名注册
  • 基于java的网站设计毕业论文正规排名网站推广公司
  • 装修设计公司哪个好关键词seo优化公司
  • 对接公众号的网站怎么做最新nba排名
  • c 做网站用什么框架百度重庆营销中心
  • 如何做网站备案网站推广软件排名
  • 查权重工具免费seo关键词优化服务