进程间的通信IPC-匿名管道pipe

进程间的通信-匿名管道pipe

管道:

实现原理: 内核借助环形队列机制,使用内核缓冲区实现。

特质: 
	1. 伪文件(不占用磁盘空间)
	2. 管道中的数据只能一次读取。
	3. 数据在管道中,只能单向流动。

局限性:
	1. 自己写,不能自己读。(不能同时进行读写操作)
	2. 数据不可以反复读。
	3. 双向半双工通信。(可以读也可以写,但同一进程只能是其中的一种)
	4. 血缘关系进程间可用。

pipe函数:
int pipe(int fd[2]);
函数功能:创建,并打开管道。
传出参数: fd[0]: 读端文件描述符。 fd[1]: 写端文件描述符。
返回值: 成功: 0; 失败: -1 errno

管道的读写行为:

读管道:

  1. 管道有数据,read返回实际读到的字节数。

  2. 管道无数据: 1)无写端,read返回0 (类似读到文件尾)
    2)有写端,read阻塞等待。

写管道:

  1. 无读端, 异常终止。 (SIGPIPE导致的)

  2. 有读端: 1) 管道已满, 阻塞等待(一般不会出现这种情况,当管道的buf满了时,内核会自动扩容)
    2) 管道未满, 返回写出的字节个数。

PS:
pipe(int fd[2])函数的传出参数是2个int型的文件描述符,故对管道进行读写操作的函数是:
写操作:
int write(fd[1],str, strlen(str)); //将str的数据写入管道

读操作:
int read(fd[0]),buf, sizeof(buf);//将管道的数据读取到buf中

关闭:

close(fd[0]);  //关闭读端
close(fd[1]); //关闭写端

父子进程共享文件描述符,在使用管道时,父进程如果想回收在进行read()的子进程时,父进程需要先**close(fd[1]);(关闭写端)**否则子进程会一直阻塞等待其他进程写入数据,进行管道读操作,所以子进程不会结束,所以父进程wait(NULL)时,也无法对子进程进行回收,会一直阻塞。(原因:读操作时,如果管道没有数据,则查看是否有写端存在,如果有,则阻塞等待写入;如果无,则返回0)

Linux命令创建管道文件:mkfifo 文件名(fifo对应的是first in first out)
创建出来的管道文件大小为0;
管道文件对应的属性是p。(-:普通文件;d:目录文件;l:符号连接文件)

附一段实现代码:功能实现ls |wc -l

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

//实现ls -rlt|wc -l功能(父进程实现ls -rlt,将数据通过管道传个子进程,子进程实现wc -l)
int main(){

    int iRet = 0;
    pid_t pid = 0;
    pid_t wpid = 0;
    int fd[2]={0,0};
    char str[100]={0};
    char sRcvBuf[1024+1]={0};
    int i = 0;
    int j = 0;

    //创建并打开管道  
    iRet = pipe( fd );
    if( -1 == iRet ){
        perror( "pipe error:" );
        exit (-1);
    }
    printf( "pipe successed!read:fd[0]=%d,write:fd[1]=%d\n", fd[0], fd[1] );

    //父子进程共享文件描述符
    for( i = 0; i < 2; i++ ){
         pid = fork( );
        if( pid == -1 ){
            perror( "fork error:" );
            exit(-1);
        }else if( pid == 0 ){
            break;
        }

        printf( "fork success;pid=%d\n", pid );

    }

    if( i == 2 ){ //父进程
        //管道规则:一个进程只能读或者只能写,不能同时读写
        //阻塞等待子进程结束,回收子进程
        sleep(2);
        close( fd[0] );  //关闭读
        close( fd[1] );   //关闭写,先关闭,不然第2个子进程的读不会结束(当所有的写端关闭后,读端才会结束,否则会阻塞等待)
        printf( "this is parent\n" );
        for( j=0;j<2;j++ ){
             wpid = wait(NULL);
             if( wpid == -1 ){
                 perror( "wait error:" );
             }
             printf( "wait pid = %d\n", wpid );
        }
        printf( "parent close success\n" );

    }else if( i == 0 ){  //第1个子进程;执行ls
        //写数据到管道 
        printf( "into 1th child\n" );
        close( fd[0] );
        dup2( fd[1], STDOUT_FILENO );
        execlp( "ls", "ls", "-lrt", NULL );
    }else if( i == 1 ){   //第2个子进程:执行wc -l
        printf( "into 2th child\n" );
        sleep(1);
        //wc命令输入后,会要求继续输入数据,然后crtl+D结束,然后统计出行数
        close(fd[1]);
        dup2( fd[0], STDIN_FILENO );
        execlp( "wc", "wc", "-l", NULL );
    }

    exit(0);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值