进程间通信之管道通信(匿名管道)

来源:互联网 发布:工作流程梳理软件 编辑:程序博客网 时间:2024/05/17 08:49
  Linux中,每个进程都有各自的地址空间及自己的用户级页表,映射到物理内存的不同地方,因此进程间互不影响,即进程间相互独立。

那么不同的进程要如何实现进程间通信呢?也就是进程间通信的本质,就是不同的进程通过看到公共资源来实现进程间通信,而这里的公共资源一般由操作系统提供,不同的提供者、提供方式也决定了通信方式的不同。
进程间有五中通信方式,分别为:匿名管道、命名管道、信号量、消息队列、共享内存。这里先介绍一下匿名管道通信。
匿名管道(pipe)
函数:int pipe(int pipefd[2]);
注:调用pipe函数时,首先在内核中开辟一块缓冲区用于通信,它有一个读端和一个写端,然后通过pipefd参数传出给用户进程两个文件描述符,pipefd[0]指向管道的读端,pipefd[1]指向管道的写段。在用户层面看来,打开管道就是打开了一个文件,通过read()或者write()向文件内读写数据,读写数据的实质也就是往内核缓冲区读写数据。

返回值:成功返回0,失败返回-1。

管道特征:
1、管道只支持单向通信
2、管道通信只能用于有血缘关系的通信,常用于父子通信,只用于父子进程的管道(匿名管道)
3、管道的生命周期随进程的结束而终止
4、管道是基于字节流通信的通信方式
5、管道内部已经实现同步机制,能够保证数据一致性(保证数据的安全性,在写数据的时候不会被别人读,不会发生二义性)

实现进程通信步骤:
1、父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端
2、父进程调用fork创建子进程,子进程也有两个文件描述符指向管道的两端
3、父进程关闭fd[0](读端),子进程关闭fd[1](写端)

例:

#include<stdio.h>#include<stdlib.h>#include<sys/wait.h>#include<sys/types.h>#include<string.h>int main(){    int fds[2];    if(pipe(fds)<0)    {        perror("pipe");        return 1;    }    pid_t id=fork();//fork创建子进程    if(id==0)    {        //child        close(fds[0]);//子进程关闭读端        const char* child="hello father,I'm child";        int i=0;        while(i<10)        {            sleep(1);            write(fds[1],child,strlen(child));            i++;        }        exit(0);    }    else    {        //father        close(fds[1]); //父进程关闭写端        char buf[1024];        while(1)        {            ssize_t s=read(fds[0],buf,sizeof(buf)-1);            if(s>0)            {                buf[s]=0;                printf("father received:%s\n",buf);            }        }    }    pid_t ret=waitpid(id,NULL,0);    if(ret>0)    {        printf("wait success!\n");    }}

运行结果:
这里写图片描述
父进程成功收到子进程写入的字符串。

使用管道时有4种特殊情况:
1、读端没关闭,读端没有读数据,写端在写数据,管道被写满时写会阻塞,直到有空了才写入数据返回(读端没有在读,写端一直在写)

代码验证:
这里写图片描述

运行结果:
这里写图片描述
父进程执行3次读操作后不再读取数据,而子进程一直在在写,管道写满时发生阻塞。

2、指向管道的进程描述符的写端没关闭,持有管道写端的进程没有向管道写数据,此时有进程从管道读端读数据,管道剩余数据读取后,再次read会阻塞,知道有数据可读才读取数据返回(读方一直在读,写方没有在写)

代码验证:
这里写图片描述
运行结果:
这里写图片描述
3、管道读端的文件描述符都关闭了,此时向管道的写端写,进程会收到信号SIGPIPE,通常导致进程异常终止
代码验证:
这里写图片描述
运行结果:
这里写图片描述
父进程的读端read3次后关闭读端,此时子进程依然在write,进程异常终止。
4、写方前期一直在写,某一时刻停止,并关闭写端,读方一直读,读到读完管道内所有数据管道结束,read返回0值,表示读到文件结尾
代码验证:
这里写图片描述
运行结果:
这里写图片描述

1 0
原创粉丝点击