【Linux进程间通信】---无名管道pipe

进程间通信IPC

进程间通信(Inter Process Communication),简称IPC
进程间通信的四种方式:

  • 管道
    匿名管道(pipe)–血缘关系进程间通信
    有名管道(fifo) --有无血缘关系均可
  • 信号
  • 共享内存–有无血缘关系均可
  • 本地套接字

匿名管道(pipe)

man pipe查询得

SYNOPSIS
       #include <unistd.h>

       int pipe(int pipefd[2]);

       #define _GNU_SOURCE             /* See feature_test_macros(7) */
       #include <fcntl.h>              /* Obtain O_* constant definitions */
       #include <unistd.h>

       int pipe2(int pipefd[2], int flags);

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned,  and  errno  is  set
       appropriately.

       On  Linux  (and  other systems), pipe() does not modify pipefd on failure.  A
       requirement standardizing this  behavior  was  added  in  POSIX.1-2016.   The
       Linux-specific  pipe2()  system call likewise does not modify pipefd on fail‐
       ure.

pipe()函数的传出参数fd[2]固定,其中,fd[0] 代表读端,fd[1] 代表写端。

  • 特质:

(1)本质为伪文件,实质为内核缓冲区,不占用磁盘空间
(2)写端流入,读端流出
(3)进程销毁则管道自动释放
(4)管道默认阻塞

  • 原理
    内核使用环形队列机制,借助内核缓冲区(4k)空间实现,先进先出

  • 局限性
    (1)单向半双工通信,数据只能单向流动
    (2)数据只能读取一次,不能重读读取
    (3)只有公共祖先的进程间才能使用
    父子进程通信实例

#include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 
  6 
  7 int main()
  8 {
  9     int fd[2];//pipe所需的文件描述符数组
 10              //成功返回文件描述符,fd[0]-r,fd[1]-w
 11     int res = pipe(fd);
 12 
 13     pid_t pid;
 14 
 15     if(res == -1)
 16     {
 17         perror("pipe error");
 18         exit(1);
 19     }
 20 
 21     pid = fork(); //进程创建成功,创建管道的进程同时掌握读和写端
 22     if(pid == -1)
 23     {
 24         perror("fork error");
 25         exit(1);
 26     }else if(pid == 0)//子进程  读数据
 27     {
 28         close(fd[1]);//读则关闭写端
 29         char buf[1024];
 30         res = read(fd[0],buf,sizeof(buf));//读出数据到buf,返回实际读取到的数据数目
 31 
 32         if(res == 0)
 33         {
 34             printf("--------\n");
 35			}
 36 
 37         write(STDOUT_FILENO, buf, res);//将buf内容写到标准输出流
 38 
 39     }else{
 40         sleep(2);
 41         close(fd[0]);//父进程,关闭读端,进行写操作
 42         char *str = "Hello pipe\n";
 43 
 44         write(fd[1], "Hello pipe\n", strlen("Hello pipe\n"));
 45 
 46     }
 47 
 48 
 49 
 50     return 0;
 51 }

代码简析:

  • 创建管道,默认阻塞,当前进程既掌控读端,也掌控写端
  • 创建子进程,根据pid返回值区分父子进程,父子进程分别关闭读端和写端,进行通信

兄弟进程间通信

  1 #include<stdlib.h>
  2 #include<stdio.h>
  3 #include<unistd.h>
  4 #include<sys/wait.h>
  5 
  6 int main(int argc, char *argv[])
  7 {
  8     pid_t pid;
  9     int fd[2];
 10     int ret = pipe(fd);//创建管道
 11 
 12     if(ret == -1)
 13     {
 14         perror("pipe error");
 15         return 0;
 16     }
 17 
 18     int i =0;
 19     for(; i < 2;i++)
 20     {
 21         pid = fork();
 22         if(pid == -1)
 23         {
 24             perror("fork error");
 25         }
 26         else if(pid == 0)
 27         {
 28             break;
 29         }
 30     }
 31 
 32     if(i == 0)//进程1
 33     {
 34         close(fd[0]);//关闭读,进行写操作
 35         dup2(fd[1],STDOUT_FILENO);//输出重定向
 36         execlp("ps", "ps", "aux", NULL);
 37 
 38     }else if(i == 1)//进程2
 39     {
 40         close(fd[1]);//关闭写,进行读操作
 41         dup2(fd[0],STDIN_FILENO);//输入重定向
 42         execlp("grep", "grep", "bash","--color=auto", NULL);
 43 
 44     }else if(i == 2)//父进程
 45     {
 46         close(fd[0]);
 47         close(fd[1]);
 48     }
 49     //回收子进程
 50 
 51     int wpid;
 52 
 53     while(wpid = waitpid(-1, NULL, WNOHANG) != -1)//调用出错返回-1
 54     {
 55         if(wpid == 1)
 56         {
 57             continue;//init进程
 58         }
 59 
 60         if(wpid == 0)
 61         {
 62             continue;//WNOHANG状态下没有已退出的子进程可供回收
 63         }
 64 
 65         printf("child pid = %d\n",wpid);//打印回收子进程号
 66 
 67 
 68     }
 69 
 70     printf("pipewrite = %d,pipered = %d\n",fd[1], fd[0]);
 71 
 72     return 0;
 73 
 74 
 75 }

此处引入内核区文件描述符的基本知识,默认0,1,2文件描述符为STDIN,STDOUT,STDERROR描述符,进程管道的文件描述符为3号和4号,分别对应读和写。

int dup2(int oldfd, int newfd);

文件描述符重定向使用dup2,将管道文件描述符重定向至标注输入输出文件描述符。
关闭进程相应的读写端
运行程序,两个子进程分别向管道内写入内容,父进程打印信息。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值