哪些企业喜欢做网站广告,产品推广方案ppt模板,抖音小程序实名认证怎么解除,注册个网站域名多少钱一年管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道” 匿名管道
#include unistd.h
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd#xff1a;文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
…管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道” 匿名管道
#include unistd.h
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0失败返回错误代码 管道文件时一种内存级文件没有名称故为匿名管道
父进程打开文件然后fork创建子进程子进程会继承父进程文件描述符表中的内容。
然后两个进程即可看到同一份文件。 一般而言管道只能用来进行单向的数据通信。
为什么让父进程以读和写的方式打开同一个文件
为了让子进程看到读写端。
int fds[2];int npipe(fds); 代码实现 //1.创建管道文件打开读写端int fds[2];int npipe(fds);assert(n0);//2.forkpid_t idfork();assert(id0);if(id0){//子进程写入close(fds[0]);const char* s子进程正在向父进程发消息;int cnt0;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));//系统接口不需要考虑\0sleep(1);}close(fds[1]);exit(0);}close(fds[1]);while(true){char buffer[1024];ssize_t sread(fds[0],buffer,sizeof(buffer)-1);if(s0)//s代表读到的字节数buffer[s]0;coutGet Message # buffer| mypid: getpid()endl;}nwaitpid(id,nullptr,0);assert(nid);close(fds[0]); 命名管道
命名管道可以从命令行上创建命令行方法是使用下面这个命令
mkfifo filename命名管道也可以从程序里创建相关函数有
int mkfifo(const char *filename,mode_t mode);
创建命名管道:
int main(int argc, char *argv[])
{mkfifo(p2, 0644);return 0;
}
comm.hpp
#pragma once#includeiostream
#includecassert
#includecstdio
#includecstring
#includestring
#includeunistd.h
#includesys/wait.h
#includesys/types.h
#includesys/stat.h
#includecerrno
#includefcntl.h
using namespace std;
#define NAMED_PIPE /tmp/mypipe.testbool createFifo(const string path)
{int nmkfifo(path.c_str(),0666);if(n0) return true;else{couterrno: errno err string: strerror(errno)endl;return false;}
}
void removeFifo(const string path)
{int nunlink(path.c_str());assert(n0);
}
server.cc
#includecomm.hppusing namespace std;int main()
{bool rcreateFifo(NAMED_PIPE);assert(r);coutserver beginendl;int rfdopen(NAMED_PIPE,O_RDONLY);coutserver endendl;if(rfd0) exit(1);//readchar buffer[1024];while (true){ssize_t sread(rfd,buffer,sizeof(buffer)-1);if(s0){buffer[s]0;coutclient-server# buffer;}else if(s0){coutclient quit , me tooendl;break;}else{couterr string--------strerror(errno)endl;break;}}close(rfd);removeFifo(NAMED_PIPE);return 0;
}
clent.cc
#includecomm.hppusing namespace std;int main()
{coutclient beginendl;int wfd open(NAMED_PIPE, O_WRONLY);coutclient endendl;if (wfd 0)exit(1);// writechar 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 1000 | sleep 2000
|:即为匿名管道
sleep的父进程为bash
综合案例
基于匿名管道的进程池设计 #includeiostream
#includevector
#includecassert
#includecstdio
#includecstring
#includectime
#includestring
#includeunistd.h
#includesys/wait.h
#includesys/types.husing namespace std;
#define PROCESS_NUM 5
#define MakeSeed() srand((unsigned long)time(nullptr))
typedef void(*func_t)();
void downLoadTask()
{coutgetpid() : downLoadTask()\nendl;sleep(1);
}
void ioTask()
{coutgetpid() : ioTask()\nendl;sleep(1);
}
void flushTask()
{coutgetpid() : flustTask()\nendl;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::num0;void sendTask(const subEp process,int taskNum)
{coutsend task num taskNum send to - process.name_endl;ssize_t nwrite(process.writeFd_,taskNum,sizeof(taskNum));assert(nsizeof(int));
}
int recvTask(int readFd)
{int code0;ssize_t sread(readFd,code,sizeof code);//assert(ssizeof(int));if(s4) return code;else if(s0) return -1;else return 0;
}
void createSubProcess(vectorsubEp* subs,vectorfunc_t funcMap)
{for(int i0;iPROCESS_NUM;i){int fds[2];int npipe(fds);//父进程打开的文件是会被子进程共享的pid_t idfork();if(id0){//子进程close(fds[1]);while (true){//1.获取命令玛如果没有子进程应阻塞int commandCode recvTask(fds[0]);//2.完成任务if(commandCode0 commandCodefuncMap.size()) funcMap[commandCode]();else if(commandCode-1) break;;}exit(0);}close(fds[0]);subEp sub(id,fds[1]);subs-push_back(sub);}
}
void loadTaskFunc(vectorfunc_t* out)
{assert(out);out-push_back(downLoadTask);out-push_back(ioTask);out-push_back(flushTask);
}
void loadBalanceContrl(const vectorsubEp subs,const vectorfunc_t funcMap,int count)
{int processnumsubs.size();int tasknumfuncMap.size();//int cntsubs.size();bool forever(count0)?true:false;while(true){//1.选择一个子进程---vectorsubEp - indexint subIdxrand()%processnum;//2.选择一个任务--- vectorfunc_t---indexint taskIdxrand()%tasknum;//3.任务发送给选择的进程sendTask(subs[subIdx],taskIdx);sleep(1);if(!forever){count--;if(count0) break;}}//write quit - read 0for(int i0;iprocessnum;i) close(subs[i].writeFd_);
}
void waitProcess(vectorsubEp processes)
{int processnumprocesses.size();for(int i0;iprocessnum;i){waitpid(processes[i].subId_,nullptr,0);coutwait sub process success ...processes[i].subId_endl;}
}
int main()
{MakeSeed();//1.建立子进程并建立和子进程通信的信道vectorfunc_t funcMap;loadTaskFunc(funcMap);vectorsubEp subs;createSubProcess(subs,funcMap);//2.父进程控制子进程int taskNum3;loadBalanceContrl(subs,funcMap,taskNum);//3.回收子进程信息waitProcess(subs);return 0;
}