目录
整体框架
通信步骤
创建管道
编辑创建子进程&关闭相应的fd
编辑
进程间通信
父子进程通信之间四种场景
实现父亲读,孩子写的进程间通信
管道通信的使用场景样例实现
整体框架
通信步骤
创建管道
pipe的参数为输出型参数,返回读写端的fd存储到pipefd的数组中,创建成功,函数返回值为0;否则为-1。
创建子进程&关闭相应的fd
进程间通信
父子进程通信之间四种场景
1. 如果读端读取完管道中的所有数据,如果写端没有发送新的数据,该读端的进程只能等待;
2.如果写端写满了管道,而读端没有来的及去读,此时的写端无法继续去写
65535=2^16==2^12 * 2^4 == 4KB*16
3. 如果关闭了写端,读取完毕管道数据,在读,read就会返回0,表示读到了文件的末尾。
4. 写端一直在写,读端关闭,会发生什么呢?写端在写就没有任何意义了。OS不会维护无意义、低效率、或者浪费资源的事情!OS会杀死一直在写的进程!OS会通过信号来终止进程,13)SIPIPE。
实现父亲读,孩子写的进程间通信
//C++函数头文件c取代.h为了更好的兼容C++
#include<iostream>
#include<cerrno>
#include<cstring>
#include<cassert>
#include<string>
//系统调用函数的头文件为.h
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
//让不同的进程看到同一个资源 步骤:1~3
//任何一种进程通信中,一定要 先 保证不同进程之间看到同一份资源 步骤:4
int pipefd[2]={0};
//1.创建管道
int ret=pipe(pipefd);
if(ret<0)
{
std::cout<<"pipe error:"<<errno<<":"<<strerror(errno)<<std::endl;
return 1;
}
//验证管道是否创建成功
std::cout<<"pipefd[0]:"<<pipefd[0]<<std::endl;//pipefd数组下标为0的表示读端
std::cout<<"pipefd[1]:"<<pipefd[1]<<std::endl;//pipefd数组下标为1的表示写端
//2.创建子进程
pid_t id=fork();
assert(id!=-1);
if(id==0)
{
//子进程
//3.关闭不需要的fd,让父进程进行读取,让子进程去写入
close(pipefd[0]);
//4.开始通信 ——结合某种场景
// const std::string nameStr="Hello ,我是子进程";
// int cnt=1;
// char buffer[1024]={0};
int cnt=0;
while(true)
{
char x='X';
write(pipefd[1],&x,1);
std::cout << "Cnt: " << ++cnt<<std::endl;
sleep(1);
//break;
// snprintf(buffer,sizeof(buffer),"%s,计数器:%d,我的pid:%d",nameStr.c_str(),cnt++,getpid());
// write(pipefd[1],buffer,strlen(buffer));
// sleep(10);
}
close(pipefd[1]);
exit(0);
}
//父进程
//3.关闭不需要的fd,让父进程进行读取,让子进程去写入
close(pipefd[1]);
//4.开始通信 ——结合某种场景
char buffer[1024]={0};
int cnt=0;
while(true)
{
//sleep(5);
int n=read(pipefd[0],buffer,sizeof(buffer)-1);
if(n>0)
{
buffer[n]='\0';
std::cout<<"我是父进程,child give me message:"<<buffer<<std::endl;
}
else if(n==0)
{
std::cout<<"我是父进程,读到了文件末尾"<<std::endl;
break;
}
else
{
std::cout<<"我是父进程,读取异常"<<std::endl;
exit(1);
}
sleep(1);
if(cnt++>5)break;
}
close(pipefd[0]);
int status=0;
waitpid(id,&status,0);
std::cout<<"sig:"<<(status&0x7F)<<std::endl;
return 0;
}
管道通信的使用场景样例实现
【应用场景】
父进程要创建若干个子进程,每一个子进程配对一个管道,用来进行与父进程之间的通信;父亲通过管道,对子进程发送信号,子进程接受到信号后,依据信号来执行相应的任务!
【问题分析】
- 如何动态创建多个子进程?答:循环控制!
- 如何建立一个管道匹配一个子进程?答:再循环里面定义临时变量pipefd[2],这样就可以确保每一个创建的子进程找到对应读写的fd!
- 由于子进程会复制父进程的所有管理对象里的内容,这样,第二个以及后面的子进程就可以得到前面子进程与父进程管道之间读写fd信息,如何确保创建的管道只对应一个子进程,不受其它子进程的影响?答:因为,父进程只能关闭读端,不能关闭写端,所以要在父进程中保存之前子进程创建管道的写端的fd,后面的创建的子进程就可以得到之前子进程的读端的fd,在依次关闭就可以了!
- 父进程如何知道给哪一个子进程来分配任务?答:为了管理多个管道和子进程与父亲的关系,方法是先描述,在组织--》描述:父亲要得到子进程的fd才能找到相应的子进程,还要得到该子进程所对应管道写端的文件描述符fd--》组织:定义EndPoint结构体存储子进程的id和文件描述符fd;在最后,每创建一个子进程,就将相应的信息存储到vector<EndPoint>容器中。
- 如何指定相对应的任务呢?答:定义task对象,里面保存要有的任务,对每一个任务进行编号处理。用户通过输入数字来指定相对应的任务!
【代码实现思路】
- 首先需要创建子进程,并创建对应的管道;
- 进程间通信,输入对应执行任务指令;
- 进程退出,回收进程。
代码实现:lesson14/2. CtrlProcess · 杰编程/LinuxCode - 码云 - 开源中国 (gitee.com)