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

西安网站开发技术深圳品牌网站制作报价

西安网站开发技术,深圳品牌网站制作报价,列表形式网站,全屋定制十大公认品牌有哪些目录 前言 1.进程间通信理论 2.使用管道进行通信 3.管道的一些信息 4.应用场景#xff1a;进程池#xff08;基于匿名管道#xff09; 5.命名管道 6.总结 前言 本篇我们开始学习linux进程间通信相关的内容#xff0c;第一篇我们要介绍的是进程间通信的理论概念以及匿…目录 前言 1.进程间通信理论 2.使用管道进行通信 3.管道的一些信息 4.应用场景进程池基于匿名管道 5.命名管道 6.总结 前言 本篇我们开始学习linux进程间通信相关的内容第一篇我们要介绍的是进程间通信的理论概念以及匿名、命名管道通信的详细操作并且我们还会基于匿名管道实现一个简单的线程池加油 1.进程间通信理论 1.什么是通信 进程间通信也叫做IPC技术 发展从单机通信到网络通信 如何理解通信的本质问题 1.操作系统需要直接或者间接给通信双方的进程提供 ”内存空间“ 2.要通信的进程必须看到一份公共的资源 通信前提要先让不同的进程看到同一份资源【某一种“内存”】我们学通信实际上是学这个 不同的通信种类 本质就是上面所说的资源是操作系统的哪一个模块提供的 2.为什么要有通信 有时候我们是需要多进程协同然后去完成某种业务内容比如 cat file | grep hello 3.怎么办 进程看到的同一份“资源”是由操作系统提供操作系统需要设计统一的通信接口这个接口要如何被调用就是我们的进程间通信的方案原则就是先统一标准后使用 进程间通信的方案 采用标准做法 POSIX —— 让通信过程可以跨主机 System V —— 聚焦在本地通信 采用文件做法让不同的进程看到同一份资源 1.管道——基于文件系统 a.匿名管道 b.命名管道 什么是管道 匿名管道不需要IO不需要刷新到磁盘上和磁盘甚至没关系为内存级文件没有所谓的名称 两进程分别以读和写方式打开同一个文件为了让子进程也能看到读写端 一般而言我们的管道只能用来进行单向数据通信所以需要分别把父子进程不需要的fd关闭 匿名管道目前能用来进行父子进程之间进程间通信 2.使用管道进行通信 管道是被操作系统单独设计的需要配上单独的系统调用 管道函数pipe 其中的pipefd为输出型参数用来存储打开文件后返回的读写两个文件描述符 成功时返回 0同时会通过传入的整数数组参数如 int pipefd[2]返回两个文件描述符pipefd[0] 用于从管道读取数据读端pipefd[1] 用于向管道写入数据写端 失败时返回 -1并设置 errno 变量以标识具体的错误原因如文件描述符用尽、参数地址不合法等 [^]  pipefd0是读取想象成嘴巴用来读pipefd1是写入想象成笔用来写  我们可以看到创建pipe管道这个文件时pipe函数是不需要传递文件路径的因为它是内存级文件压根不需要文件路径也就是说也不需要文件名所以叫做匿名管道 那没有文件名要怎么去保证两个进程打开的是同一个管道文件呢答子进程继承父进程文件描述符表 各种 ‘printf’ 前面几种的区别是把内容格式化到特定的文件或是字符串内第一种printf就是格式化显示到显示器上 3.管道的一些信息 管道的5种特性 匿名管道只能用来进行具有”血缘关系“的进程进行进程间通信通常是父子 管道文件自带同步机制后面多线程详谈 管道是面向字节流的 管道是单向通信的——属于半双工的一种特殊情况 a. 任何一个时刻一个发一个收——半双工 b. 任何一个时刻可以同时发收——全双工 (管道)文件的生命周期是随进程的进程一旦结束所打开的文件就被操作系统关闭 管道的4种通信情况 写慢读快——读端就要阻塞进程要等写端 写快读慢——写端就要阻塞进程要等读端 以上两种情况是因为管道的同步机制这一特性形成的 写关继续读——read就会读到返回值\0也就是0表示文件结尾如果让nread()那么n的值此时就为0 读关继续写——写端在写入没有任何意义os不会做没有意义的事情所以这种情况发生之后操作系统会杀掉写端进程然后发送异常信号13-SIGPIPE 管道的容量 [^]  也就是65536/102464kb  管道的写入原子性 管道写入的原子性是指当进程向管道写入数据时若数据量不超过 PIPE_BUF如 Linux 中为 4096 字节POSIX 规定至少 512 字节该写入操作要么完全成功数据全部写入要么完全失败数据未写入不会出现部分写入的情况 4.应用场景进程池基于匿名管道 池化技术 可以减少我们创建对应某种资源的成本提高访问时的效率 如果父进程把所有任务都分配给一个子进程——负载不均衡 我们要雨露均沾地分配任务——负载均衡 几种方式实现均衡 轮询 随机 channel添加负载指标 进程池信道的建立 #pragma once #include iostream #include cstdlib //cstdlib-stdlib.h #include vector #include unistd.h using namespace std; ​ //.hpp后缀可以使得方法实现和声明在一个文件这样Main.cc在调用时只需要包含.hpp头文件 ​ // 进程池 ​ // 对信道管道进行管理 // 先描述描述管道信息 class channel { public:channel(int fd, pid_t id): _wfd(fd),_subid(id){// 使用to_string将fd和id都转成字符加到后面作为名字一部分_name channel- to_string(_wfd) - to_string(_subid);} ​~channel() {} ​// 外部需要拿到channel内部的信息我们需要一些get方法int Fd() { return _wfd; }pid_t SubId() { return _subid; }string Name() { return _name; } ​ private:// 每个管道都需要有对应的文件描述符int _wfd;// 还需要知道对应的子进程的idpid_t _subid;// 以及为了之后方便打印提示消息对应管道的名字string _name; };​ // 要创建多少个进程池 const int gdefaultnum 5; ​ // 再组织管理信道管道的接口类我们这里通过vector数据结构来组织 class ChannelManager { public:ChannelManager() {}~ChannelManager() {} ​void Insert(int wfd, pid_t subid){// 构建一个channel然后push到组织的vector数组中(先描述再组织)// channel c(wfd, subid);//_channels.push_back(move(c)); //c为临时对象应该使用右值引用减少拷贝// 或者也可以使用vector容器中提供的emplace_back方法// 直接调用内部构造函数帮我们创建一个对象在插入vector中_channels.emplace_back(wfd, subid);} ​// 打印_channels中各channel的信息的方法void PrintChannels(){for (auto channel : _channels){cout channel.Name() endl;}} ​ private:// 通过vector来组织vectorchannel _channels; };​ // 进程池类 class ProcessPool { public:ProcessPool(int num): _process_num(num){} ​~ProcessPool() {} ​// 子进程要做的工作void Work(int rfd){// 伪工作while (true){cout 我的rfd是: rfd endl;sleep(5);}} ​// 创建进程池方法bool Create(){// 要创建process_num个进程for (int i 0; i _process_num; i){// 1. 创建管道int pipefd[2] {0};int n pipe(pipefd);if (n 0){return false;} ​// 2. 创建子进程// 子进程读父进程写int subid fork();if (subid 0)return false;else if (subid 0){// 子进程// 3. 关闭写端close(pipefd[1]);Work(pipefd[0]); // 子进程要做的读端相关工作close(pipefd[0]); ​// 执行完直接退出// 不会干扰for循环只有父进程会一直循环创建执行循环内代码exit(0);}else{// 父进程// 3. 关闭读端close(pipefd[0]);// 需要在ChannelManager内部把我们的fd和subid信息传入创建的channel中// 再由ChannelManager把创建好的channel插入到数组中// 所以在ChannelManager类中需要Insert方法来完成上述操作// 其中我们父进程对应的fd文件描述符是写端pipefd[1]_cn.Insert(pipefd[1], subid);}}// 创建成功return true;} ​// Debug方法中查看每个channel信道管道的信息void Debug(){// 调用ChannelManager中的PrintChannels方法_cn.PrintChannels();} ​ private:// 进程池类内部需要包含我们的通信信道// 所以我们通过管理通信信道的类创建一个对象在进程池内部ChannelManager _cn;// 要创建的进程池对应的进程的个数这样就能确定管道的个数int _process_num; }; 采用轮询的方式使得负载平衡 进程池相关完整源代码可以看ProcessPool  5.命名管道 匿名管道只能用来进行具有血缘关系的进程进行进程间通信常用于父子进程 如果两个进程不相关该如何进行通信呢 通过上图其实我们就已经通过打开同一路径下的同一个文件来做到让不同的进程看到了同一份资源进程间通信的前提而因为文件有路径使得这个路径下文件具有唯一性通过路径来区分、有名字——所以这种通信的方式叫做——命名管道 我们一般文件是要刷新到磁盘的我们的命名管道这种作为通信的文件是不能被刷新的所以命名管道需要一种特殊的文件——管道文件只会被打开不需要刷新 我们通过mkfifo命令来创建管道文件也就是命名管道 echo和cat在执行时就是进程shell运行原理不管是不是内建命令它都是进程 所以上图中我们就利用命名管道完成了一次进程间通信echo将hello fifo重定向输入然后cat重定向输出从fifo中显示内容到终端上 我们可以通过unlink命令来删除管道文件 我们在代码上可以通过mkfifo接口来创建管道文件 记住这里的第一个参数是c语言格式的字符如果用string对象得调用c_str() 路径加名字就构成我们要构建的命名管道了 string fifoname _path / _name; int n mkfifo(fifoname.c_str(), 0666); [^]  上图内容不理解没关系我们在网络部分才会进一步去理解  同样的我们在代码上可以用unlink函数来关闭管道文件 [^]  关闭成功返回0失败返回-1和mkfifo创建返回逻辑是一样的  简单用命名管道通信代码 comm.hpp #pragma once ​ #define FIFO_FILE fifo server.cc #include sys/stat.h #include sys/types.h #include unistd.h #include iostream #include string #include fcntl.h #include comm.hpp using namespace std; ​ int main() {umask(0);// 新建管道int n mkfifo(FIFO_FILE, 0666);if (n ! 0){cerr mkdir fifo error endl;return 1;}cout mkfifo success endl; ​// 以读打开管道文件// write方没有执行open时read方就要在open内部阻塞// 直到有人把管道文件打开了open才会返回int fd open(FIFO_FILE, O_RDONLY);if (fd 0){cerr open fifo error endl;return 2;}cout open fifo success endl; ​// 正常读取char buffer[1024];while (true){int number read(fd, buffer, sizeof(buffer) - 1);if (number 0){// 我们把读到内容当成字符串所以得在n位置加上\0buffer[number] \0;cout client say: buffer endl;}else if (number 0){cout client quit! me too number endl;break;}else{cerr read error endl;break;}} ​// 关闭管道文件close(fd); ​// 删除管道文件n unlink(FIFO_FILE);if (n 0){cout remove fifo success endl;}else{cout remove fifo failed endl;} ​return 0; } client.cc #include sys/stat.h #include sys/types.h #include unistd.h #include iostream #include string #include fcntl.h #include comm.hpp using namespace std; ​ int main() {// client端不需要创建管道文件了因为我们在server端已经创建好了int fd open(FIFO_FILE, O_WRONLY);// 剩下的都是文件操作了if (fd 0){cerr open fifo error endl;return 2;} ​// 写入操作string message;int cnt 1;pid_t id getpid();while (true){cout Please Enter# ;getline(cin, message);message (,message number: to_string(cnt) ,[ to_string(id) ]); ​// c_str()用于将string对象转换为 C 风格的字符串即以空字符\0结尾的字符数组int n write(fd, message.c_str(), message.size());if (n 0){}} ​close(fd); ​return 0; } 我们需要先执行server编译后的可执行程序来创建命名管道而后它会阻塞在open那块因为命名管道需要两个进程来同时打开我们这里write方没有执行open时read方就要在open内部阻塞直到有人把管道文件打开了open才会返回所以接下来我们需要在另一个终端上执行client编译后的可执行程序就达到了用命名管道实现进程间通信从客户端进程向服务端进程发送消息的简单效果 当我们关闭写端client时读端的number就为0了然后也跟着退出后删除管道文件 6.总结 命名管道和匿名管道的区别 其他的特性是完全和匿名管道一样的只有一点不同那就是命名管道可以用来进行让不相关进程进行进程间通信命名管道也可以用来实现文件的拷贝
http://www.hkea.cn/news/14388674/

相关文章:

  • 建网站后如何运营wordpress钉钉
  • 梵讯企业网站建设wordpress zip 升级
  • 做易购网站凡科网域名续费
  • 太原企业网站排名xampp上传Wordpress
  • 包装设计网站设计平台建设银行个人查询
  • dw制作网站网络推广竞价是什么
  • 戴尔网站建设成功项目开发的主要流程步骤
  • 自助广告位网站源码网站搭建品牌
  • 网站链接是什么百度网盘网页版入口
  • 苏州木渎做网站公司个人网站与企业网站
  • 东阳网站建设yw126梵克雅宝手链
  • 山大优秀网站建设2018年度本地wordpress 手机浏览器
  • 网站开发公司流程做网站编辑如何写好一篇新闻
  • 三星杭州 两学一做网站仿网站源码
  • 网站源码开发推广普通话奋进新征程
  • 如果在阿里云上做自己的网站做新的网站seo
  • 做微网站迅宇科技wordpress作者权限拿shell
  • 上海网站推广大全抖音代运营怎么取消
  • 怎样做网站上的语种链接wordpress后台目录无法访问
  • 网站升级建设方案西安高校定制网站建设公司推荐
  • 做筹款的网站需要什么资质汉中市住建局建设厅网站官网
  • 做微商海报的网站这个网站 做学术检索非常棒
  • 学院网站建设需求分析调研表人工智能公众号
  • 滕州做网站的广东省建筑企业资质查询平台
  • 营销型网站怎么收费东莞今天特大新闻
  • 网站视频建设一键网站制作app
  • 成都网站排名提升优秀产品设计案例
  • 买了个域名 如何建网站网站页面两侧漂浮的怎样做
  • 网站开发的初级技术员网站建设的策划文案
  • wordpress 网站很慢wordpress免费中文主题分享