Linux进程间通信之匿名管道
文章目录
0.思考题
- 全局变量,父子进程之间是否可以相互访问?
- 父子进程在内存占用的是否为同一块内存空间?
一般而言,我们可以认为每个进程享有独立的内存空间(如果子进程只读数据Linux 系统会优化使得父子进程占据同一块区域,这一情况不在我们考虑范围之内)。
因为,各自占据一块内存,因此每个进程都有一个 4G 虚拟内存(32位系统),即每个进程有自己的全局区
、堆区
、栈区
等。由此,父子进程是无法相互访问各自的全局变量(因为各自有自己的全局区)。
- 那个,如果父子进程进程之间如何进数据传递呢?
常用的进程间数据传递方法如下:
管道
、消息队列
、信号量
、共享内存
等。
本文,余下章节将介绍基于管道
的进程间数据通信。
1.基本概念
由于连个进程各自拥有自己独立的内存空间,因此无法直接进行数据传递。类似于交换两个变量需要中间变量
,同理,我们可以找到一个中转站
,使用中转站来进行数据传递。此中转站
需要两个两个进程都可以访问到。
管道技术,就是基于上述基本思路。何为管道?类似于现实中的管道,此处的管道,即为两个进程之间可以进行数据传递的一条通道。
管道的本质是内核中的一段缓冲区,即我们上文所述的中转站
。
这段缓冲区,由两个文件描述符引用,一个文件描述如Pipefd[1]
负责写数据,一个文件描述符如Pipefd[0]
负责读数据。
2.管道函数 pipe 介绍
2.1 函数原型
#include <unistd.h>
int pipe(int pipefd[2]);
2.2 函数功能
pipe
函数用来创建一个有血缘关系
的进程之间通信管道.
何为有血缘关系
的进程?
如父子进程
、兄弟进程
等。
2.3 形参解释
形参 int pipefd[2]
是一个整数数组,其本质是一个传出参数。
pipefd[0]
:管道读端文件描述符pipefd[1]
:管道写端文件描述符
2.4 返回值解释
- 成功返回 :
0
- 失败返回:
-1
,并且设置 相应的errno
3.案例程序之父子进程通信
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int result = -1; // 创建管道结果
int fd[2]; // 管道创建后得到的文件描述符
result = pipe(fd); // 创建管道
if(-1 == result){
perror("pipe");
return -1;
}
pid_t pid = fork();
if(-1 == pid){
perror("fork");
return -1;
}else if(0 == pid){
// 子进程
// 为了使得子进程负责读,需要关闭子进程中 pipe 的写端
close(fd[1]);
// 循环读父进程的数据
char buf[1024] = {0};
size_t count = 1024;
int ret = read(fd[0], buf, count);
// 将读到数据写到 终端
//write(STDOUT_FILENO, buf, strlen(buf));
printf("%s", buf);
close(fd[0]);
}else{
// 父进程
// 我们指定父进程只进行写数据,因此我们要关闭 pipe 的读端
close(fd[0]);
// 将 buf 中的内容写入到 管道写端
char buf[1024] = "hello pipe test.\n";
int ret = write(fd[1], buf, strlen(buf));
if(-1 == ret){
perror("write");
return -1;
}
printf("The parent is over.\n");
}
return 0;
}
程序运行结果: