马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
管道
管道是Unix中最古老的进程间通讯的情势。
我们把从一个进程毗连到另一个进程的一个数据流称为一个“管道”
匿名管道
- #include <unistd.h>
- 功能:创建一无名管道
- 原型
- int pipe(int fd[2]);
- 参数
- fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
- 返回值:成功返回0,失败返回错误代码
复制代码
管道文件时一种内存级文件,没著名称,故为匿名管道
父进程打开文件然后fork创建子进程,子进程会继续父进程文件形貌符表中的内容。
然后两个进程即可看到同一份文件。
一样寻常而言管道只能用来举行单向的数据通讯。
为什么让父进程以读和写的方式打开同一个文件?
为了让子进程看到读写端。- int fds[2];
- int n=pipe(fds);
复制代码
代码实现
- //1.创建管道文件打开读写端
- int fds[2];
- int n=pipe(fds); assert(n==0); //2.fork pid_t id=fork(); assert(id>=0); if(id==0) { //子进程写入 close(fds[0]); const char* s="子进程,正在向父进程发消息"; int cnt=0; while(true) { cnt++; char buffer[1024]; snprintf(buffer,sizeof buffer,"child->parent say: %s[%d][%d]",s,cnt,getpid()); write(fds[1],buffer,sizeof(buffer));//体系接口不须要思量'\0' sleep(1); } close(fds[1]); exit(0); } close(fds[1]); while(true) { char buffer[1024]; ssize_t s=read(fds[0],buffer,sizeof(buffer)-1); if(s>0)//s代表读到的字节数 buffer[s]=0; cout<<"Get Message # "<<buffer<<"| mypid: "<<getpid()<<endl; } n=waitpid(id,nullptr,0); assert(n==id); close(fds[0]);
复制代码
定名管道
定名管道可以从下令行上创建,下令行方法是使用下面这个下令:定名管道也可以从步调里创建,干系函数有:- int mkfifo(const char *filename,mode_t mode);
复制代码 创建定名管道:- int main(int argc, char *argv[])
- {
- mkfifo("p2", 0644);
- return 0;
- }
复制代码 comm.hpp- #pragma once
- #include<iostream>
- #include<cassert>
- #include<cstdio>
- #include<cstring>
- #include<string>
- #include<unistd.h>
- #include<sys/wait.h>
- #include<sys/types.h>
- #include<sys/stat.h>
- #include<cerrno>
- #include<fcntl.h>
- using namespace std;
- #define NAMED_PIPE "/tmp/mypipe.test"
- bool createFifo(const string& path)
- {
- int n=mkfifo(path.c_str(),0666);
- if(n==0) return true;
- else
- {
- cout<<"errno: "<<errno<<" err string: "<<strerror(errno)<<endl;
- return false;
- }
- }
- void removeFifo(const string& path)
- {
- int n=unlink(path.c_str());
- assert(n==0);
- }
复制代码 server.cc- #include"comm.hpp"
- using namespace std;
- int main()
- {
- bool r=createFifo(NAMED_PIPE);
- assert(r);
- cout<<"server begin"<<endl;
- int rfd=open(NAMED_PIPE,O_RDONLY);
- cout<<"server end"<<endl;
- if(rfd<0) exit(1);
- //read
- char buffer[1024];
- while (true)
- {
- ssize_t s=read(rfd,buffer,sizeof(buffer)-1);
- if(s>0)
- {
- buffer[s]=0;
- cout<<"client->server# "<<buffer;
- }
- else if(s==0)
- {
- cout<<"client quit , me too"<<endl;
- break;
- }
- else
- {
- cout<<"err string--------"<<strerror(errno)<<endl;
- break;
- }
- }
-
- close(rfd);
- removeFifo(NAMED_PIPE);
- return 0;
- }
复制代码 clent.cc- #include"comm.hpp"
- using namespace std;
- int main()
- {
- cout<<"client begin"<<endl;
- int wfd = open(NAMED_PIPE, O_WRONLY);
- cout<<"client end"<<endl;
- if (wfd < 0)
- exit(1);
- // write
- char buffer[1024];
- while (true)
- {
- cout << "Please Say# ";
- fgets(buffer, sizeof(buffer), stdin);
- if(strlen(buffer)>0) buffer[strlen(buffer)-1]=0;
- ssize_t n = write(wfd, buffer, strlen(buffer));
- assert(n == strlen(buffer));
- }
- close(wfd);
- return 0;
- }
复制代码 管道的读写特性
1. (读慢,写快)如果管道中没有了数据,读端在读,默认会直接壅闭当前正在读取的进程
2.(读快,写慢)管道是一个固定巨细的缓冲区,写端写满时会壅闭,期待对方读取
3.(写端关闭,读到0)读端将数据读完后读到0竣事进程。
4.读关闭,在写就没故意义了,OS会给写进程发送信号(13),将其制止。
管道的特性
1.管道的声明周期随进程
2.管道可以用来举行具有血缘关系的进程之间举行通讯,常用于父子通讯
3.管道是面向字节省的。按设置的最大字节数去读。
4.管道通讯---半双工|:即为匿名管道
sleep的父进程为bash
综合案例
基于匿名管道的进程池筹划
 - #include<iostream>
- #include<vector>
- #include<cassert>
- #include<cstdio>
- #include<cstring>
- #include<ctime>
- #include<string>
- #include<unistd.h>
- #include<sys/wait.h>
- #include<sys/types.h>
- using namespace std;
- #define PROCESS_NUM 5
- #define MakeSeed() srand((unsigned long)time(nullptr))
- typedef void(*func_t)();
- void downLoadTask()
- {
- cout<<getpid()<<" : downLoadTask()\n"<<endl;
- sleep(1);
- }
- void ioTask()
- {
- cout<<getpid()<<" : ioTask()\n"<<endl;
- sleep(1);
- }
- void flushTask()
- {
- cout<<getpid()<<" : flustTask()\n"<<endl;
- sleep(1);
- }
- class subEp
- {
- public:
- subEp(pid_t subId,int writeFd)
- :subId_(subId),writeFd_(writeFd)
- {
- char nameBuffer[1024];
- snprintf(nameBuffer,sizeof nameBuffer,"process-%d[pid(%d)-fd(%d)]",num++,subId_,writeFd_);
- name_=nameBuffer;
- }
- public:
- static int num;
- string name_;
- pid_t subId_;
- int writeFd_;
- };
- int subEp::num=0;
- void sendTask(const subEp& process,int taskNum)
- {
- cout<<"send task num "<<taskNum<<" send to -> "<<process.name_<<endl;
- ssize_t n=write(process.writeFd_,&taskNum,sizeof(taskNum));
- assert(n==sizeof(int));
- }
- int recvTask(int readFd)
- {
- int code=0;
- ssize_t s=read(readFd,&code,sizeof code);
- //assert(s==sizeof(int));
- if(s==4) return code;
- else if(s<=0) return -1;
- else return 0;
- }
- void createSubProcess(vector<subEp>* subs,vector<func_t>& funcMap)
- {
- for(int i=0;i<PROCESS_NUM;++i)
- {
- int fds[2];
- int n=pipe(fds);
- //父进程打开的文件是会被子进程共享的
- pid_t id=fork();
- if(id==0)
- {
- //子进程
- close(fds[1]);
- while (true)
- {
- //1.获取命令玛,如果没有,子进程应阻塞
- int commandCode = recvTask(fds[0]);
- //2.完成任务
- if(commandCode>0 && commandCode<funcMap.size()) funcMap[commandCode]();
- else if(commandCode==-1) break;;
- }
- exit(0);
- }
- close(fds[0]);
- subEp sub(id,fds[1]);
- subs->push_back(sub);
- }
- }
- void loadTaskFunc(vector<func_t>* out)
- {
- assert(out);
- out->push_back(downLoadTask);
- out->push_back(ioTask);
- out->push_back(flushTask);
- }
- void loadBalanceContrl(const vector<subEp>& subs,const vector<func_t> &funcMap,int count)
- {
- int processnum=subs.size();
- int tasknum=funcMap.size();
- //int cnt=subs.size();
- bool forever=(count==0)?true:false;
- while(true)
- {
- //1.选择一个子进程--->vector<subEp> -> index
- int subIdx=rand()%processnum;
- //2.选择一个任务---> vector<func_t>--->index
- int taskIdx=rand()%tasknum;
- //3.任务发送给选择的进程
- sendTask(subs[subIdx],taskIdx);
- sleep(1);
- if(!forever)
- {
- count--;
- if(count==0) break;
- }
- }
- //write quit -> read 0
- for(int i=0;i<processnum;++i) close(subs[i].writeFd_);
- }
- void waitProcess(vector<subEp> processes)
- {
- int processnum=processes.size();
- for(int i=0;i<processnum;++i)
- {
- waitpid(processes[i].subId_,nullptr,0);
- cout<<"wait sub process success ..."<<processes[i].subId_<<endl;
- }
- }
- int main()
- {
- MakeSeed();
- //1.建立子进程并建立和子进程通信的信道
- vector<func_t> funcMap;
- loadTaskFunc(&funcMap);
- vector<subEp> subs;
- createSubProcess(&subs,funcMap);
- //2.父进程控制子进程
- int taskNum=3;
- loadBalanceContrl(subs,funcMap,taskNum);
- //3.回收子进程信息
- waitProcess(subs);
- return 0;
- }
复制代码 |