一、进程间通信

每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程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. linux系统编程之管道(一):匿名管道(pipe)

    一,什么是管道 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管道: 只能用于父子进程或者兄弟进程之间(具有 ...

  2. 进程间通信之管道(pipe、fifo)

    我们先来说说进程间通信(IPC)的一般目的,大概有数据传输.共享数据.通知事件.资源共享和进程控制等.但是我们知道,对于每一个进程来说这个进程看到属于它的一块内存资源,这块资源是它所独占的,所以进程之 ...

  3. VC 模拟CMD 匿名管道

    #include "stdafx.h" #include <Windows.h> #include <stdio.h> #include <stdli ...

  4. Linux进程间通信(三):匿名管道 popen()、pclose()、pipe()、close()、dup()、dup2()

    在前面,介绍了一种进程间的通信方式:使用信号,我们创建通知事件,并通过它引起响应,但传递的信息只是一个信号值.这里将介绍另一种进程间通信的方式——匿名管道,通过它进程间可以交换更多有用的数据. 一.什 ...

  5. 体验usually.js的管道函数——pipe函数

    体验usually.js的管道函数——pipe函数 usually.js 是一个面向现代 Web 开发的 JavaScript 函数库,基于 ES6 开发.最新版本2.4.1,最新版本usually. ...

  6. Linux学习笔记(12)-进程间通信|匿名管道

    Linux的进程间通信有几种方式,包括,管道,信号,信号灯,共享内存,消息队列和套接字等-- 现在一个个的开始学习! ----------------------------------------- ...

  7. Windows下 C++ 实现匿名管道的读写操作

    由于刚弄C++没多久,部分还不熟练,最近又由于开发需求要求实现与其他程序进行通信,瞬间就感觉想到了匿名通信.于是自己查阅了一下资料,实现了一个可读可写的匿名管道: 源代码大部分都有注释: Pipe.h ...

  8. Linux进程间通信-匿名管道

    前面我们讲了进程间通信的一种方式,共享内存.下面看一看另一种机制,匿名管道.1.什么是管道管道是一个进程的数据流到另一个进程的通道,即一个进程的数据输出作为另一个进程的数据输入,管道起到了桥梁的作用. ...

  9. IPC——匿名管道

    Linux进程间通信——使用匿名管道 在前面,介绍了一种进程间的通信方式:使用信号,我们创建通知事件,并通过它引起响应,但传递的信息只是一个信号值.这里将介绍另一种进程间通信的方式——匿名管道,通过它 ...

随机推荐

  1. Android -- 在ScrollView中嵌套ListView

    在做一个工程,这个工程的布局可以相当的复杂,最外面是ScrollView,在ScrollView里面有两个Listview,这下好了,布局出来了,放在机子上跑,卡得想死有木有,信息乱跑乱出现,表示非常 ...

  2. 【Ansible】Playbook实例

    Learn to build Ansible playbooks with our guide, one step at a time In our previous posts, we introd ...

  3. Oracle根据字段值找到表名和列名

    方法1: --Oracle 根据字段值查询其所在的表.字段 DECLARE CURSOR cur_query IS SELECT table_name, column_name, data_type ...

  4. PCL源码剖析之MarchingCubes算法

    原文:http://blog.csdn.net/lming_08/article/details/19432877 MarchingCubes算法简介 MarchingCubes(移动立方体)算法是目 ...

  5. JavaScript 与 PHP 的语法区别

    1. 基本类型 php的基本类型分别: .基本数据类型:整型.小数(float/double).字符串.布尔类型 .复合类型:数组.对象 .特殊类型:Null,资源类型 JavaScript的基本类型 ...

  6. [android错误] Failed to install *.apk on device 'emulator-5554': timeout

    [2014-06-26 15:35:42 - app] ------------------------------ [2014-06-26 15:35:42 - app] Android Launc ...

  7. C#.NET常见问题(FAQ)-delegate委托链如何使用

    委托链本质就是你把一堆要执行的东西放到一个list里面,当要触发一组事情的时候,就不需要一个一个写一遍了(比如厂里食堂开饭了,这个方法一执行,要让厨师A时间在食堂等候打饭,B类员工在某个时间排队打饭, ...

  8. linux内核——进程管理

    在讲进程之前先说一下进程的堆栈的吧: 1.进程的堆栈 内核在创建进程的时候,在创建task_struct的同一时候,会为进程创建对应的堆栈.每一个进程会有两个栈,一个用户栈.存在于用户空间,一个内核栈 ...

  9. 远程连接Ubuntu桌面配置

    1.打开终端:依次安装 sudo apt-get install xrdp sudo apt-get install vnc4server tightvncserver sudo apt-get in ...

  10. 笔试题之xml

    XML部分 1.xml有哪些解析技术?区别是什么? 答:有DOM,SAX,STAX等 DOM:处理大型文件时其性能下降的非常厉害.这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM ...