底层逻辑:
父进程与子进程是相互独立的,子进程无法直接给父进程传递信息,但是父进程和子进程可以访问同一块磁盘文件,如果子进程更改了磁盘文件,父进程就可以通过访问该文件来进行交互,进而实现通信。
因为1.这个中间文件只是用来交互,没有其他实际作用,2.从磁盘书写和更改文件的代价过大。所以这个中间文件最好存储在内存。
操作系统不允许两个进程直接访问同一块内存空间,如果同时访问会发生写实拷贝,但是操作系统会提供一些特殊的接口来允许一些特殊关系的进程访问同一块内存,这是操作系统层面的,所以可以绕过页表
图解:
1
2
3![](https://i-blog.csdnimg.cn/blog_migrate/4387768e63559d5a38a324d68c217406.png)
代码模拟实现
#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
const int size = 1024;
std::string getOtherMessage(){
static int cnt = 0;
std::string messageid = std::to_string(cnt);
cnt++;
pid_t self_id = getpid();
std::string stringpid = std::to_string(self_id);
std::string message = "messageid: ";
message+=messageid;
message+="mypid is : ";
message+=stringpid;
return message;
}
void SubProcessWrite(int wfd){
std::string message = "Father, I am your son process";
while(true)
{
std::string info = message + getOtherMessage();
write(wfd,info.c_str(),info.size()); //这里没有写入末尾的'/0',也没有必要写
sleep(1);
}
}
void FatherProcessRead(int rfd){
char inbuffer[size];
while(true)
{
size_t n = read(rfd,inbuffer,sizeof(inbuffer)-1 ); //预留一个写/0
if(n > 0)
{
inbuffer[n] = 0;
std::cout<<"father get message: "<< inbuffer <<std::endl;
}
}
}
int main(){
//创建管道
int pipefd[2];
int n = pipe(pipefd);
if(n != 0)
{
std::cerr<<"errno: "<<errno<<";"<<"errstring: "<<strerror(errno)<<std::endl;
return 1;
}
std::cout<<"pipefd[0]:"<<pipefd[0]<<";"<<"pipefd[1]"<<pipefd[1]<<std::endl;
sleep(1);
pid_t id =fork();
if(id == 0)
{
std::cout<<"准备通信"<<std::endl;
sleep(1);
//子进程 --- wirit
close(pipefd[0]); //关闭读文件
SubProcessWrite(pipefd[1]);
close(pipefd[1]); //关闭写文件
exit(0);
}
//父进程 -----read
sleep(1);
close(pipefd[1]); //关闭写文件
FatherProcessRead(pipefd[0]);
pid_t rid = waitpid(id,nullptr,0);
if(rid > 0)
{
std::cout<<"父进程等待成功,子进程已退出。"<<std::endl;
}
close(pipefd[0]); //关闭读文件
return 0;
}