• 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 }
  • 相关阅读:
    Java 匿名内部类
    【嘎】数组-搜索插入位置
    【嘎】数组-1266. 访问所有点的最小时间
    【嘎】数组-1313. 解压缩编码列表
    【嘎】数组-1431. 拥有最多糖果的孩子
    element-ui下拉多选报错Error in event handler for "handleOptionClick": "TypeError: value.push is not a function"
    【嘎】数组-有效的山脉数组
    【嘎】数组-打家劫舍
    【嘎】字符串-字符串中的第一个唯一字符
    linux
  • 原文地址:https://www.cnblogs.com/SeekHit/p/6709383.html
Copyright © 2020-2023  润新知