欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

进程间通信-匿名管道

程序员文章站 2024-03-01 13:03:58
...

匿名管道

一、特点

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;
}

进程间通信-匿名管道

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