进程间通信-匿名管道

来源:互联网 发布:linux qt调试器未设置 编辑:程序博客网 时间:2024/05/16 17:54

匿名管道

一、特点

1.只适合单向通信。(如果需要双向通信,则需要两个匿名管道来进行完成)

2.只适合具有血缘关系的进程进行通信

3.管道是文件,生命周期随进程,进程结束后,文件就不在了

4.管道是基于字节流方式来进行通信的

5.父进程和子进程访问的公共资源叫做临界资源,所有临界资源都是需要被保护起来的,多个进程进行访问时必须要保证原子性。(任一时刻保证只有一个人访问)

6.管道内部自己已经实现同步性,能保证数据的一致性。

另外,进程间的通信的本质是:两个进程看到了一份公共的资源。

二、管道的创建

1.由父进程创建,子进程继承父进程的文件描述符,指向同一个文件,一个用来读,一个用来写,适当的关闭相应的文件读写端。
这里写图片描述
这里写图片描述

函数功能:创建管道,使得__pipe[0]指向文件的读端,_pipe[1]指向文件的写端
参数:一个含有两个整型元素的数组
返回值:0正常 -1管道创建失败
2.管道的大小
测试匿名管道的大小:

#include<stdio.h>#include<unistd.h>#include<stdlib.h>int main(){        int fd[2];        int count=0;        if(pipe(fd)<0)        {                perror("Fail to create pipe");                exit(1);        }        while(1)        {                write(fd[1],"a",sizeof(char));                printf("count=%d.\n",++count);        }        return 0;}

这里写图片描述

可知:管道的大小是:65536个字节=2的16次方个字节=64M

三、关于匿名管道读写的四种方式

使⽤用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):

1. 如果所有指向管道写端的⽂文件描述符都关闭了(管道写端的引⽤用计数等于0),⽽而仍然有进程 从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到⽂文件末尾⼀一样。

#include<stdio.h>#include<errno.h>#include<string.h>#include<sys/wait.h>#include<unistd.h>int main(){        int _pipe[2];        int ret=pipe(_pipe);        if(ret==-1)        {                printf("create pipe error ! error code is :%d\n",errno);        }        pid_t id=fork();        if(id<0)        {                printf("fork error\n");                return 2;        }        else if(id==0)//child        {                close(_pipe[0]);                int i=0;                char * _mesg_c=NULL;                while(i<10)                {                        sleep(1);                        _mesg_c="i am child";                        write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);                        i++;                }        close(_pipe[1]);        }        else//father        {                close(_pipe[1]);                char _mesg[100];                int j=0;                printf("child id ;%d\n",id);                while(j<100)                {                        memset(_mesg,'\0',sizeof(_mesg));                        read(_pipe[0],_mesg,sizeof(_mesg)-1);                        printf("%s:code count :%d\n",_mesg,j);                        j++;                }        }        if(waitpid(id,NULL,0)<0)        {                printf("wait child sucessfully\n");                return 3;        }        return 0;}

这里写图片描述
可以看出父进程读取时,发生了阻塞,每隔一秒钟读取一次。

2.如果有指向管道写端的⽂文件描述符没关闭(管道写端的引⽤用计数⼤大于0),⽽而持有管道写端的 进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

#include<stdio.h>#include<errno.h>#include<string.h>#include<sys/wait.h>#include<unistd.h>int main(){        int _pipe[2];        int ret=pipe(_pipe);        if(ret==-1)        {                printf("create pipe error ! error code is :%d\n",errno);        }        pid_t id=fork();        if(id<0)        {                printf("fork error\n");                return 2;        }        else if(id==0)//child        {                close(_pipe[0]);                int i=0;                char * _mesg_c=NULL;                while(i<20)                {                        if(i<10)                        {                        _mesg_c="i am child";                        write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);                        }                        sleep(1);                        i++;                }    //  close(_pipe[1]);        }        else//father        {///     sleep(3);                close(_pipe[1]);                char _mesg[100];                int j=0;                printf("child id ;%d\n",id);                while(j<20)                {                        memset(_mesg,'\0',sizeof(_mesg));                        read(_pipe[0],_mesg,sizeof(_mesg)-1);                        printf("%s:code count :%d\n",_mesg,j);                        j++;                }        }        if(waitpid(id,NULL,0)<0)        {                printf("wait child sucessfully\n");                return 3;        }        return 0;}

这里写图片描述

3.如果所有指向管道读端的⽂文件描述符都关闭了(管道读端的引⽤用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终⽌止。

#include<stdio.h>#include<errno.h>#include<string.h>#include<sys/wait.h>#include<unistd.h>int main(){        int _pipe[2];        int ret=pipe(_pipe);        if(ret==-1)        {                printf("create pipe error ! error code is :%d\n",errno);        }        pid_t id=fork();        if(id<0)        {                printf("fork error\n");                return 2;        }        else if(id==0)//child        {                close(_pipe[0]);                int i=0;                char * _mesg_c=NULL;                while(i<20)                {                        if(i<10)                        {                        _mesg_c="i am child";                        write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);                        }//                      sleep(1);                        i++;                }        }        else//father        {                close(_pipe[1]);                char _mesg[100];                int j=0;                printf("child id ;%d\n",id);                while(j<3)                {                        memset(_mesg,'\0',sizeof(_mesg));                        read(_pipe[0],_mesg,sizeof(_mesg)-1);                        printf("%s:code count :%d\n",_mesg,j);                        j++;                }                close(_pipe[0]);        }        if(waitpid(id,NULL,0)<0)        {                printf("wait child sucessfully\n");                return 3;        }        return 0;}

这里写图片描述
进程异常终止

4.如果有指向管道读端的⽂文件描述符没关闭(管道读端的引⽤用计数⼤大于0),⽽而持有管道读端的 进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再 次write会阻塞,直到管道中有空位置了才写⼊入数据并返回。

#include<stdio.h>#include<errno.h>#include<string.h>#include<sys/wait.h>#include<unistd.h>int main(){        int _pipe[2];        int ret=pipe(_pipe);        if(ret==-1)        {                printf("create pipe error ! error code is :%d\n",errno);        }        pid_t id=fork();        if(id<0)        {                printf("fork error\n");                return 2;        }        else if(id==0)//child        {                close(_pipe[0]);                int i=0;                char * _mesg_c=NULL;                while(i<20)                {                        _mesg_c="i am child";                        write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);                        sleep(1);                        i++;                }        }        else//father        {                close(_pipe[1]);                char _mesg[100];                int j=0;                printf("child id ;%d\n",id);                while(j<5)                {                        memset(_mesg,'\0',sizeof(_mesg));                        read(_pipe[0],_mesg,sizeof(_mesg)-1);                        printf("%s:code count :%d\n",_mesg,j);                        j++;                }        }        if(waitpid(id,NULL,0)<0)        {                printf("wait child sucessfully\n");                return 3;        }        return 0;}

这里写图片描述

写入端发生阻塞,一直等待读取。

0 0