进程间通信之匿名管道

来源:互联网 发布:触摸屏 手势软件 编辑:程序博客网 时间:2024/06/07 06:11

我们知道每个进程都有各自 的进程地址空间,一个进程看不到另外一个进程的全局变量,那么要实现进程之间的数据交换,必须要通过内核,首先内核要先开辟缓冲区,进程1先把数据拷贝到内核的缓冲区中,进程2再从缓冲区中把数据拿走,内核提供的这种机制就叫做进程间通信。
这里写图片描述

管道是一种基本的IPC机制,用于创建管道的函数为pipe;

#include <unistd.h>int pipe(int filedes[2]);

调用pipe函数首先要在内核开辟一块缓冲区用于通信,他有一个读端,一个写段,通过filedes参数传出给用户程序两个文件描述符,filedes[0]表示管道读端,filedes[1]表示管道写端,通过read(filedes[0]);或者write(filedes[1]);向这个⽂文件读写数据其实是在读写内核缓冲区。pipe函数调⽤用成功返回0,调⽤用失败返回-1。
创建管道的过程如下:
这里写图片描述
1.首先父进程调用pipe来创建管道,同时得到2个文件描述符指向读端与写段。
2.父进程调用fork创建子进程,子进程继承父进程的文件描述符表,同样子进程也有两个文件描述符指向管道的两端。
3.父进程关闭读端,子进程关闭写段(或者父进程关闭写段,子进程关闭读端)
4.管道使用环形队列实现的,数据从写段流入,从读端流出,这样就形成了进程间的通信机制。
但是这样有一个问题,管道式单双工的,数据传输是单方向的,只能一方写,一方读,不能进行双向通信。管道的读写端要通过打开的文件描述符传递,要通信的两个进程必须要继承公共祖先的文件描述符才能进行通信,所以管道一般用于有关系的进程之间的通信,一般是父子进程之间的通信。
使用管道要注意一下4中特殊情况:
1.如果所有指向管道写端的文件描述符都关闭了,而仍然有进程从管道里读数据,当管道数据为空时,在此读会返回0,就像读到文件结尾一样。
2.如果有指向管道写端的文件描述符没有关闭,持有管道写端的进程也没有像管道中写入数据,那么对管道进行读操作,当管道中的数据被读完之后,read就会阻塞式等待,直到管道中有数据为止。
3.如果所有只想读端的文件描述符全部关闭,仍然有进程向管道中写数据,那么该进程就会收到SIGPIPE信号,会导致进程异常终止。
4.如果有指向管道读端的文件描述符没有关闭,持有管道读端的进程也没有读管道中数据,那么对管道进行写操作,当管道被写满时,write就会阻塞式等待,直到管道有空间为止。
实现代码如下:

#include <stdio.h>#include <unistd.h>#include <string.h>int main(){    int pp[2]={0};    if(pipe(pp)<0)    {        perror("pipe");        return -1;    }    pid_t id=fork();    if(id==0)    {        close(pp[0]);//child->write        char* msg="hello,I am child";        while(1)        {            write(pp[1],msg,strlen(msg));            sleep(1);        }    }    else//father->read    {        close(pp[1]);        char buf[1024];        while(1)        {            ssize_t s=read(pp[0],buf,sizeof(buf)-1);            if(s>0)        {            buf[s]=0;            printf("%s\n",buf);        }        }    }    return 0;}

此代码是让子进程写,父进程每隔一秒读一次,结果如下:
这里写图片描述