前言
上回书说到,父进程创建完子进程后,两个进程就分家了,各过各的,进程间无法实现数据交流。
实际应用中我们经常会遇到需要进程间传递信号或数据的情况,有什么办法可以实现进程间通信呢?
无名管道
无名管道本质上是一个队列
该队列存在于内核中,父子进程通过向内核里的这个队列读写数据,来实现通信,如图所示:
创建无名管道所需的函数:
int pipe(int pipefd[2]);
该函数返回值:
- -1:创建失败
- 0:创建成功
该函数参数为一个整型数组,长度为2
这个数组可以返回创建的管道信息:pipefd[0]表示管道队头文件描述符,pipefd[1]表示管道队尾文件描述符。
有了这两个文件描述符,就简单了。
例如:父进程要告知子进程:我这边事情干完了,该你了。
那么,父进程就往pipefd[1],队尾写一个标志位。
子进程在pipefd[0]队头那边等了半天,一看,哎呀,终于等来了,一看,是干活的标志位,好,开始干活。
下面的代码实现:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int fd[2];
int ret;
int inter_prces=0;
pid_t pid;
ret = pipe(fd); //先创建一个无名管道
if(ret<0){
printf("creat pipe failed.\n");
return -1;
}
printf("creat pipe sucess.fd[0]=%d,fd[1]=%d.\n",fd[0],fd[1]);
pid = fork(); //再创建一个子进程
if(pid>0){ //父进程中打印5句话,接着往管道写标志位inter_prces
for(int i=0;i<5;i++){
printf("parent process %d\n",i);
}
sleep(5);
inter_prces = 1;
write(fd[1],&inter_prces,sizeof(inter_prces));
}
if(pid==0){ //子进程等待管道发来的数据,直到收到inter_prces置1
read(fd[0],&inter_prces,sizeof(inter_prces));
while (inter_prces==0); //注意:子进程里的inter_prces变量和父进程中的同名变量没有关系
for(int i=0;i<5;i++){
printf("child process %d\n",i);
}
}
close(fd[0]);
close(fd[1]);
return 0;
}
以上,就是通过无名管道实现的进程间通信的过程。
无名管道 附加说明
- 管道,顾名思义,它是有容量极限的,一下子往里写的太多,会出现写阻塞,就是说,写满管道后,无法继续写入,进程会进入睡眠状态;同样的,管道里啥都没有时,也会出现读阻塞,进程睡眠,等待管道发来数据。
- 管道内的数据,读一个,少一个,读完了,管道就空了。如果只发一个数据,读两次,第二次会因为读不到数据,而进入阻塞状态。
- 使用多进程间无名管道通信时,必须先创建管道,再创建子进程。如果先创建子线程,子进程则会创建自己的管道,和父进程的管道不是同一个,自然也就没办法通信。
- 无名管道只能用在有亲缘关系的进程之间,无亲缘关系的进程是无法通过无名管道通信的,要想通信,可以使用有名管道。