一、进程间通信

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

二、管道是一种最基本的IPC机制,由pipe函数创建:
#include <unistd.h>

int pipe(int filedes[2]);

调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。

开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信。

示例程序如下:

C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 
/*************************************************************************
    > File Name: process_.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(int argc, char *argv[])
{
    int pipefd[2];
    if (pipe(pipefd) == -1)
        ERR_EXIT("pipe error");

pid_t pid;
    pid = fork();
    if (pid == -1)
        ERR_EXIT("fork error");

if (pid == 0)
    {
        close(pipefd[0]);
        write(pipefd[1], "hello", 5);
        close(pipefd[1]);
        exit(EXIT_SUCCESS);
    }

close(pipefd[1]);
    char buf[10] = {0};
    read(pipefd[0], buf, 10);
    printf("buf=%s\n", buf);

return 0;
}

1. 父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端。
2. 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。
3. 父进程关闭管道写端,子进程关闭管道读端。子进程可以往管道里写,父进程可以从管道里读,管道是用环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通信。

三、利用pipe和dup2函数模拟命令行 ls  | wc -w 功能

C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 
/*************************************************************************
    > File Name: process_.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(int argc, char *argv[])
{
    int pipefd[2];
    if (pipe(pipefd) == -1)
        ERR_EXIT("pipe error");

pid_t pid;
    pid = fork();
    if (pid == -1)
        ERR_EXIT("fork error");

if (pid == 0)
    {
        dup2(pipefd[1], STDOUT_FILENO); //输出重定向
        close(pipefd[1]);
        close(pipefd[0]);
        execlp("ls", "ls", NULL);
        fprintf(stderr, "error execute ls\n");
        exit(EXIT_FAILURE);
    }

dup2(pipefd[0], STDIN_FILENO);
    close(pipefd[0]);
    close(pipefd[1]);
    execlp("wc", "wc", "-w", NULL);
    fprintf(stderr, "error execute wc\n");
    exit(EXIT_FAILURE);

return 0;
}

我们知道命令行 ls | wc -w 中 ls 会输出到管道,而wc 从管道里读取,现在使用dup2复制文件描述符,使ls 的标准输出为管道,wc 的标准输入也为管道,即使父进程先被调度,因为默认是阻塞I/O操作,故wc 会read 阻塞直到管道被子进程写入了数据。

使用管道有一些限制:

两个进程通过一个管道只能实现单向通信,比如最上面的例子,父进程读子进程写,如果有时候也需要子进程读父进程写,就必须另开一个管道。

管道的读写端通过打开的文件描述符来传递,因此要通信的两个进程必须从它们的公共祖先那里继承管道文件描述符。上面的例子是父进程把文件描述符传给子进程之后父子进程之间通信,也可以父进程fork两次,把文件描述符传给两个子进程,然后两个子进程之间通信,总之需要通过fork传递文件描述符使两个进程都能访问同一管道,它们才能通信。

参考:《APUE》、《linux c 编程一站式学习》

匿名管道和pipe函数相关推荐

  1. 匿名管道(pipe)和命名管道(mkfifo)

    匿名管道(pipe)和命名管道(mkfifo) 进程间通信必须通过内核提供的通道. 1.匿名管道 匿名管道通过打开的文件描述符来标识的.--用于具有亲缘关系间进程之间的通信. int pipe(int ...

  2. Linux进程通信——匿名管道、命名管道、管道的特性和共享内存

    Linux进程通信--匿名管道.命名管道.管道的特性和共享内存 一.管道 1.1 什么是管道? 1.2 匿名管道 <1> 匿名管道参数说明 <2> fork共享管道原理 < ...

  3. Linux_进程间通信(进程间通信,匿名管道,命名管道)

    文章目录 1.进程间通信 1.1 进程间通讯概述 1.2 进程间通信目的 1.3 进程间通信分类 2. 管道 2.1 概述 2.2 匿名管道 2.2.1 概述 2.2.2 创建匿名管道 2.2.3 基 ...

  4. 【编撰】linux IPC 002 - 匿名管道PIPE和有名管道FIFO的概念和实例,以及应用比较

    前言:上一节提到IPC的概述,本一节,原文作者比较详细的讨论了,管道的概念和实例和使用场景: 原文作者:郑彦兴 (mlinux@163.com)国防科大计算机学院 http://www.ibm.com ...

  5. MFC匿名管道原理详解、函数总结、调用实例(用MFC的匿名管道读取CMD输出内容)(C++语言)

    本博客主要总结MFC中匿名管道的原理和具体调用实例,以及调用匿名管道三个核心函数各个参数用法详解,具体的如下所述. 博主在做项目时,遇到一个问题.用程序调用一个进程,然后读取进程输出信息.但是,博主用 ...

  6. Linux中父子进程、兄弟子进程之间通信方式--匿名管道pipe(适用于有血缘关系的进程)

    文章目录 编程环境: 进程间通信 IPC: 匿名管道(pipe): 父子进程间通信: 兄弟子进程间通信: 管道的读写行为: 读操作: 写操作: 查看管道缓冲区大小: 设置管道的非阻塞属性: 下载地址: ...

  7. 进程间通信(匿名管道、命名管道、共享内存)

    进程间通信 进程间通信的作用 管道 匿名管道 命令感受匿名管道 从内核角度去解释匿名管道 代码创建匿名管道 从PCB角度去分析匿名管道 匿名管道的非阻塞读写特性 创建管道,获取管道读写两端文件描述符的 ...

  8. Linux——匿名管道、命名管道及进程池概念和实现原理

    目录 一.什么是匿名管道 二.如何使用匿名管道 (一).pipe原理 (二).pipe使用 三.命名管道概念及区别 (一).什么是命名管道 (二).与匿名管道的联系和区别 四.命名管道的使用 (一). ...

  9. 【Linux】进程间通信--管道(匿名管道和命名管道)

    文章目录 前言 进程间通信的目的 管道 匿名管道 管道特点 站在文件描述符角度理解管道 匿名管道通信读写特点 命名管道 命名管道的原理 命名管道的创建 命名管道完成两个不同进程通信 匿名管道和命名管道 ...

最新文章

  1. DATEADD(Day, DATEDIFF(Day,0,ShippingTime), 0)
  2. mysql mgr监控_说MGR - MGR的监控
  3. 【Flink】Failed to create checkpoint storage at checkpoint coordinator side
  4. jeecgboot 前端环境搭建_如何从零开始搭建前端监控平台?
  5. by mybatis 自定义order_springboot2结合mybatis拦截器实现主键自动生成
  6. eplan和西门子plc的对接_基于EPLAN的西门子电路图高效设计
  7. jsessionid的删除
  8. 从产品模式到生活方式,苏宁小Biu车联网迈过了哪些坎?
  9. ​九月简报 | Coinversation先行版DEX——Kaco上线碎片化,TVL最高突破1000w美金
  10. [Oracle] 一个通过添加本地分区索引提高SQL性能的案例
  11. systemd 知:介绍
  12. 利用梆梆加固逻辑漏洞取巧脱壳
  13. correl函数_Excel表格技巧—CORREL函数的使用经验分享
  14. CGB2109-Day10-mybatis
  15. A hybrid method of exponential smoothing and recurrent
  16. 软件框架-无绪开发4
  17. 机器学习入门之流浪地球
  18. 用BeanShell实现公式管理-使用Java脚本构建强大、灵活的公式管理系统[转]
  19. 详解numpy中的array(附实例源码)
  20. 银行卡OCR API推荐

热门文章

  1. JS 数据类型转换、创建对象
  2. ubuntu16.04下安装mysql详细步骤
  3. python中文注释
  4. ELK学习笔记之Kibana权限控制和集群监控
  5. 2.1 maven配置多镜像地址
  6. 自动化部署之jenkins及简介
  7. leetcode 103. 二叉树的锯齿形层次遍历
  8. java byte 梳理
  9. iOS发展系列II - UILabel 使用摘要
  10. JavaEE实战班第十七天