linux 匿名管道实现亲缘间进程间通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_40921797/article/details/82593565

进程间为什么要通信交流?

要了解进程间通信,首先必须对进程有一定的了解,具体什么是进程参见博客:linux什么是进程
那么进程为什么要通信呢?首先就进程本事来说,它是具有独立性的,他有自己独有的PCB具体到linux下就是,独立的task_struct。它有自己独立的虚拟地址对照表那么多个进程数据交换就会很困难。但是就实际工作而言,一个系统中,往往就是很多个进程协同工作的,这些进程必要就要 进行信息交流。所以进程间通信,就变得尤为重要。

进程间通信目的

完成数据传输(一个进程向另一个进程发送数据)、
数据共享(两个进程共享同一段数据资源),
通知事件(一个进程给另一个进程或者进程组发送消息,叫通知)、
进程控制(有些进程希望完全控制另一个进程的进行,可以实时监测状态改变,完成拦截异常等操作)

管道

管道实际上就是内核中的一块缓冲区,通过进程从管道中放数据,取数据来完成进程中数据资源的传输。
管道的特点是:单向通信,也就是说传输数据的一方,就只能传输数据,接收数据就只能接收数据。
这里写图片描述

匿名管道

匿名管道,就是没有名字的管道,没有名字两个不相干的进程是无法传输数据的。我往这里放了,可以你也不知道到哪里取呀。所以匿名管道的适用范围就是父子进程等有亲缘关系的进程间通信。
什么是父子进程,如何创建参见博客linux 父子进程

创建匿名管道

#include<unistd.h>

int pipe( int fd[2]);
/*参数:两个参数fd,是文件描述符数组,fd[0]代表从管道读数据的读端,fd[1]代表向管道写数据的写端。
返回值:成功返回0,失败返回错误代码。*/

调用pipe在亲缘进程间具体操作原理。以父子进程为例子:因为是通过fork创建的子进程时,将父进程的PCB重新拷贝了一遍,在fork创建子进程前,调用pipe函数。
为什么不能fork后创建呢?
因为fork前的函数只有父进程会调用,而fork后的函数则是分别调用,那么调用的就不是同一个管道了,而且随便他们共有同一代码段,但是数据独享。这也决定了要在fork前创建。
调用后,返回两个接口,也就是fd[0],fd[1]也就说,无论是父进程子进程此时都有这两个接口,而我们知道管道是单向传输,所以需要我们手动关闭不需要的一方读写操作符。
因为fd是文件描述符,所以我们可以利用open,close等文件接口操作。记住文件当我们使用完,也要关闭。

这里写图片描述
假如,我们是父进程写入,子进程读取。我们需要手动关闭父进程的fd[0],子进程的fd[1]。
这里写图片描述
对以上例子的代码简单实现:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
int main()
{
     int fd[2];
     //建管道
     if(pipe(fd) < 0)
     {
         perror("pipe error");
         return -1;
     }
     //创建子进程
     int pid = -1;
     pid = fork();
     if(pid < 0)
     {
         return -1;
     }
     else if(pid == 0)
     {
     //子进程
         close(fd[1]);
         char buff[1024] = {0};
         read(fd[0],buff,1024);
         //从fd[0]管道中读取数据并打印
         printf("child:%s\n",buff);
         close(fd[0]);
     }
     else
     {
         close(fd[0]);
         sleep(1);
         //向fd[1]管道中写入数,sleep的原因的此时,子进程从管道读取数据时,没有读到会阻塞式等待有进程向管道中写入。
         write(fd[1],"hello ",6);
         write(fd[1],"world",5);
         sleep(1);
//让父进程晚于子进程退出,虽然这里可能产生僵尸进程,是不对的。但是这里避免了子进程变成孤儿进程(后台运行)。输出异常的情况。
         close(fd[1]);
     }
     return 0;
 }

运行结果:
这里写图片描述

匿名管道特点

1.无论是匿名管道还是命名管道都是半双工的单向通信,一方写入,一方读。
2.匿名管道仅适用于亲缘关系的管道。
3.管道自带同步(对临界资源访问的时序控制)与互斥(对临界资源的同一时间的唯一访问性)特性。
4.读写特性:
1.读数据:如果管道没有数据可以读,则阻塞等待,除外描述符被设置为非阻塞则不会阻塞而是报错返回
2.写数据:如果管道数据已经满了,则阻塞式等待有数据读出后写入,如果被设置为非阻塞则报错返回
3.读数据:如果写端被关闭,则读完管道中的数据并自动终止读操作返回0。
4.写数据:如果读端被关闭,则写时会触发异常,返回信号迫使进程推出。
5.写数据:若同时写入的数据大于一定的大小时,则写操作不再是原子操作,写操作可以被打断。

猜你喜欢

转载自blog.csdn.net/weixin_40921797/article/details/82593565