须熟知文件管理和进程方面的基础知识
通过Xshell和VScode 相互进行远程开发,学习进程间通信的其中一种方式——管道。
依照我们曾经所学的知识,我们仅仅只能在单个进程中进行数据的交互,但是在实际应用中,单个进程不说不能实现一个产品的全部功能,但是会十分糅杂且出现问题很难定位。
而我们从以往学习的知识中,我们了解到进程之间是十分具有独立性的,例如父子进程各自修改重叠数据会有写实拷贝,所以,我们如果要进行进程间通信,其实成本是较为巨大的,但是又是尤为重要。
那么对于以后的开发,我们就要学会多进程乃至多线程通信交互,而今天,我们来学习多进程间通信的第一种方式——管道。
管道,是原生Linux系统提供的一个进程间通信的方式,一般使用于父子进程当中
管道的原理就是父子进程打开同一块文件,我们称这个文件叫做"管道"。因为父子进程由于进程的独立性,基本上从数据方面可以说是互不干扰,那么就可以由操作系统帮我们打开一个文件,让父子进程同时看到一块同样的管道文件区域,再通过这个管道文件实现通信。
需要注意的是,管道是单向的,且不止可以仅连接两个进程,可以连接多个进程。
pipe(管道)
int pipefd[2] = {0};
int ret = pipe(pipefd);
首先我们来看pipe函数的参数,pipefd是一个空间为2的int数组,如果我们在一些编程题网站做过题目,就应该知道“输出型参数”,而这里的pipefd就是充当输出型参数。
输出型参数:将需要从函数内部运行过程中的数据通过输出型参数来获取出来,比如说一个函数可以有返回值,但是我们如果需要从一个函数获取不止一个变量的数据甚至不同类型的数据,那么输出型参数就可以帮我们解决这个问题。
例如这里的pipe函数,我们需要将管道函数帮我们打开的管道通信文件的fd获取,这样我们才可以进行通信
这里的pipefd[0]是代表着管道的读端,pipefd[1]代表着管道的写端
返回值代表是否成功创建一个管道,如果返回值为-1,则管道创建失败。
#include<iostream>
#include<unordered_map>
#include<sys/types.h>
#include<sys/unistd.h>
#include<sys/wait.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
using namespace std;
int main()
{
int pipefd[2] = {0}; //pipefd[0] 读端 pipefd[1] 写端
int ret = pipe(pipefd);
assert(ret != -1);
#ifdef DEBUG
cout << "pipefd[0]:"<< pipefd[0] <<endl;
cout << "pipefd[1]:"<< pipefd[1] <<endl;
#endif
int fd = fork();
assert(fd != -1);
if(fd > 0)
{
//父进程 进行读操作
//1.关闭写的fd
close(pipefd[1]);
//开辟缓冲区
char buffer_read[1024*8];
//进行读操作
while(1)
{
int len = read(pipefd[0],buffer_read,sizeof(buffer_read)-1);
if(len > 0)
{
buffer_read[len] = '\0';
}
cout<< "父进程:"<<buffer_read<<endl;
}
waitpid(fd,nullptr,0);
}
else if(fd ==0){
//子进程 进行写操作
//1.关闭读的fd
close(pipefd[0]);
//2.1开辟缓冲区
char buffer_write[1024*8];
//2.2传输的小溪
string message = "I am son, i am writing message for father!";
//进行写操作
int count = 0;
while(1)
{
//snprintf 初始化缓冲区
snprintf(buffer_write,sizeof(buffer_write),"%s:%d",message.c_str(),++count);
//开始向文件缓冲区进行写数据
write(pipefd[1],buffer_write,strlen(buffer_write));
sleep(1);
}
exit(0);
}
return 0;
}