IPC 进程间通信方式——管道

进程间通信概述

  • 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间
  • 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
  • 通知时间:一个进程需要向另一个或一组进程发送消息,通知他们发生了某些事件(如进程终止时要通知父进程)
  • 资源共享:多个进程之间共享同样的资源,为了做到这一点,需要内核提供锁和同步机制
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入的异常,并能够及时指导它的状态改变。
 

进程间通信方式

  • 管道(pipe),有名管道(FIFO)
  • 信号(signal)
  • 消息队列
  • 共享内存
  • 信号量
  • 套接字(socket)
 

管道

  • 管道针对本地计算机的两个进程之间的通信而设计的通信方式,管道建立后,实际获得两个文件描述符:一个用于读取另一个用于写入。
  • 常见的IPC机制,通过pipe系统调用。
  • 管道单工,数据只能向一个方向流动。双向通信时,需要建立两个管道。
  • 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道的缓冲区的尾部,每次都是从缓冲区的头部读出数据。
 

管道的分类

  • 匿名管道 
    • 关系进程,父子或兄弟
    • 由pipe系统调用,管道由父进程建立
    • 管道位于内核空间,其实是一块缓存
  • 有名管道(FIFO) 
    • 两个没有任何关系的进程之间通信可通过有名管道进行数据传输
    • 通过系统调用mkfifo创建
 

管道创建

 
  1. #include<unistd.h>
  2. int pipe(int fd[2]);
  3. //返回:0成功,-1出错
  • 两个文件描述符数组 
    • fd[0]:pipe的读端
    • fd[1]:pipe的写端

管道通信是单向的阻塞性IO

借助管道使两个子进程相互通讯

  • 一个子进程调用execvp函数,将执行结果写入管道
  • 另外一个子进程也是调用execvp函数,从管道中读取命令结果进行过滤。
  • 涉及改变标准输入输出,重定向。

$ cat /etc/passwd |grep root

 
 1 #include <unistd.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 char *cmd1[3]={"/bin/cat","/etc/passwd",NULL};
 6 char *cmd2[3]={"/bin/grep","root",NULL};
 7 
 8 int main(void)
 9 {
10     int fd[2];
11     if(pipe(fd)<0)
12     {
13         perror("pipe error");
14         exit(1);
15     }
16     int i=1;
17     pid_t pid;
18     for(;i<=2;i++)
19     {
20         pid=fork();
21         if(pid<0)
22         {
23             perror("fork error");
24             exit(1);
25         }
26         else if(pid==0)
27         {
28             //child process
29             if(i==1)
30             {
31                 //子进程1,负责写入数据
32                 close(fd[0]);//关闭读端
33                 
34                 //将标准输出重定向到管段的写端
35                 if(dup2(fd[1],STDOUT_FILENO)
36                             !=STDOUT_FILENO)
37                 {
38                     perror("dup2 error");
39                 }
40                 close(fd[1]);
41 
42                 //调用exec函数执行cat命令
43                 if(execvp(cmd1[0],cmd1<0))
44                 {
45                     perror("excvp error");
46                     exit(1);
47                 }
48                 break;
49             }
50             if(i==2)
51             {
52                 //子进程2,负责从管道读取数据
53                 close(fd[1]);//关闭写端
54                 
55                 //将标准输入重定向到管道的读端
56                 if(dup2(fd[0],STDIN_FILENO)
57                                 !=STDIN_FILENO)
58                 {
59                     perror("dup2 error");
60                 }
61                 close(fd[0]);
62 
63                 //调用exec函数执行grep命令
64                 if(execvp(cmd2[0],cmd2)<0)
65                 {
66                     perror("execvp error");
67                     exit(1);
68                 }
69                 break;
70 
71             }
72         }else
73         {
74             //parent process
75             if(i==2)
76             {
77                 //父进程要等到子进程全部创建完毕才去回收
78                 close(fd[0]);
79                 close(fd[1]);
80                 wait(0);
81                 wait(0);
82             }
83         }
84     }
85 }
原文地址:https://www.cnblogs.com/SeekHit/p/6709383.html