Linux 进程间通信 ---- 管道

管道(pipe):
    常说的管道(pipe)也叫匿名管道,管道的作用于有血缘关系的父子进程或者兄弟进程,通过fork来传递。调用pipe()函数时,会再内核开辟一块缓冲区(称为管道)用于通信,大小为64KB(手动测出来的,只写不读,最多能写65520字节),它有一个读端一个写端,然后通过fd参数传出给用户程序两个文件描述符,fd[0]指向读端,fd[1]指向写端。所以管道在用户程序看起来就像打开一个文件,用过read(fd[0])或write(fd[1]),向这个文件读写数据,其实是在读写内核缓冲区。pipe()函数成功返回0,失败返回-1。


管道特点:
    1、他是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端;
    2、他只能用于有血缘关系的进程之间的通信,如兄弟进程,父子进程,实现依赖父子进程间资源共享;
    3、管道内部有保证数据同步的机制,从而保证访问数据的一致性;
    4、他可以看做是一种特殊的文件,对它的读写也可以使用普通的read\write函数。但是他不普通文件,并不属于任何文件系统,并且只存在于内存中;
    5、管道随着进程,进程在管道在,进程消失管道对应的端口也关闭,两个进程都消失,管道也消失。
    
管道实现通信的原理:
    1、父进程创建管道,得到两个文件描述符,指向管道两端
    2、父进程fork出子进程,子进程也有两个文件描述符指向同一个管道
    3、父进程关闭fd[0]读端,子进程关闭fd[1]写端,因为管道只只 支持单向通信。父进程往管道中写,子进程往管道中读,这样就实现了进程间通信
但是有如下几种情况需要注意(前提条件是父子进程都没有退出,提出后相应的fd会被关闭,对应的情况就是fd被关闭的情况):
    1、如果有指向管道读端的文件描述符没有关闭(管道读端引用计数大于0),此时有进程通过写端文件描述符向管道内写入数据,若是没有进程从读端读取数据,那么管道被写满后就会被阻塞,直到管道内有空余的位置后才写入数据并返回。
    2、如果所有指向管道读端的文件描述符都被关闭(管道读端引用计数为0),此时有进程通过写端文件描述符向管道内些数据时,此时该进程会收到SIGPIPE信号,并异常终止。
    3、如果有指向管道写端的文件描述符没有被关闭(管道写端引用计数大于0),而持有管道写端的进程没有向管道内写数据,若是此时有进程从管道读端毒数据,那么读完管道内的剩余数据后就会阻塞等待,直到有数据可读才读取数据返回。
    4、如果所有指向管道写端的文件描述符都关闭了(管道写端引用计数为0),而仍然有进程从管道读端读取数据,那么管道内的数据被读完后,再次读取,read就会返回0,就像督导文件结尾。

例子:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main()
{
    int fd[2];
    int ret = pipe(fd);
    if(ret < 0)
    {
        perror("pipe error \n");
        return -1;
    }
    
    pid_t pid = fork();
    if(pid == 0)
    {
        int i=0;
        close(fd[0]);
        char *child="I am child!";
        while(i < 10)
        {
            write(fd[1], child, strlen(child)+1);
            i++;
            sleep(1);
        }
    }
    else if(pid >0)
    {
        close(fd[1]);
        char msg[100];
        int status=0;
        int j=0;
        while(j<5)
        {
            memset(msg, 0, sizeof(msg));
            ssize_t s = read(fd[0], msg, sizeof(msg));
            if(s > 0)
            {
                msg[s-1] = '\0';
            }
            
            printf("%s %d\n", msg j);
        }
        
        close(fd[0]);
        
        pid_t ret=waitpid(pid, &status, 0);
        printf("exitsingle(%d), exit(%d) \n", status&0xff, (status >> 8)&0xff);
        //低8位存放该子进程退出时是否收到信号
        //高8位存放子进程退出时的退出码
    }
    else
    {
        perror("fork error \n");
        return -1;
    }
    
    return 0;
}

 

以上知识点均摘抄自网络,如若侵权,请私信联系删除

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值