linux多进/线程编程(4)——进程间通信之pipe和fifo

 

前言:

Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。

 

 

 

常用的进程间通信方式有:

① 管道 (使用最简单)

② 信号 (开销最小)

③ 共享映射区 (无血缘关系)

④ 本地套接字 (最稳定) https://zhuanlan.zhihu.com/p/336734605

本文主要讲解pipe管道的用法和代码示例。

管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
  1. 其本质是一个伪文件(实为内核缓冲区) 
  2. 由两个文件描述符引用,一个表示读端,一个表示写端。
  3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。

 

管道的局限性:

1. 数据一旦被读走,便不在管道中存在,不可反复读取。
2. 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
3. 只能在有公共祖先的进程间使用管道。

 

pipe

NAME
       pipe, pipe2 - create 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);

 利用pipe实现ps aux | grep bash

int pipe_fd[2];
  pipe(pipe_fd);

  pid_t pid = fork();

  if (pid == 0) {
    //son  -----> 这里会产生僵尸进程
    //管道的使用规范:关闭读端
    close(pipe_fd[0]);
    //1.先重定向
    dup2(pipe_fd[1], STDOUT_FILENO);//标准输出重定向到管道写端
    //2.execlp
    execlp("ps", "ps", "aux", nullptr);
  } else if (pid > 0) {
    //parent
    //管道的使用规范:关闭写端
    close(pipe_fd[1]);
    //1.先重定向
    dup2(pipe_fd[0], STDIN_FILENO);//标准输入重定向到管道读端
    //2.execlp   -----> grep 会阻塞
    execlp("grep", "grep", "--color=auto", "bash", nullptr);
    //代码的问题:父进程认为还有写端存在,就有可能还有人给发数据,继续等待
    //管道的使用规范
  }

 

 

 

fifo 可以实现无血缘关系的进程间通信

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>


int main(int argc, char * argv[]) {
  if (argc != 2) {
    printf("./a.out fifonname\n");
    return -1;
  }
  //当前目录有一个myfifo文件 
  //打开fifo文件
  int fd = open(argv[1], O_WRONLY);
  //
  char buf[256];
  int num = 1;
  while(1) {
    memset(buf, 0x00, sizeof(buf));
    //循环写
    sprintf(buf, "xiaoming%04d", num++);
    write(fd, buf, strlen(buf));
    sleep(1);
  }

  //关闭描述符
  closde(fd);

  return 0;
}

 

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>


int main(int argc, char * argv[]) {
  if (argc != 2) {
    printf("./a.out fifonname\n");
    return -1;
  }
  //当前目录有一个myfifo文件 
  //打开fifo文件
  int fd = open(argv[1], O_RDONLY);

  char buf[256];
  int ret = 0;
  while(1) {
    //循环读
    ret = read(fd, buf, sizeof(buf));
    if (ret > 0) {
      printf("read:%s\n", buf);
    }
  }

  //关闭描述符
  closde(fd);

  return 0;
}

 

posted @ 2021-04-07 18:34  胖白白  阅读(471)  评论(0编辑  收藏  举报