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

<a href="http://www.emacsvi.com/wp-content/uploads/2015/10/IPC_pipe_ie.jpg"><img src="http://www.emacsvi.com/wp-content/uploads/2015/10/IPC_pipe_ie.jpg" alt="IPC_pipe_ie" width="288" height="176" class="alignnone size-full wp-image-291" /></a>

<h4> 管道 pipe()函数 </h4>
管道是一种最基本的IPC机制,由pipe函数创建:

<pre lang="c" escaped="true">
#include <unistd.h>

int pipe(int pipefd[2]);
</pre>

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

<blockquote>int pipe(int filedes[2]) 中的两个文件描述符被强制规定filedes[0]只能指向管道的读端,如果进行写操作就会出现错误;同理filedes[1]只能指向管道的写端,如果进行读操作就会出现错误.</blockquote>

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

<a href="http://www.emacsvi.com/wp-content/uploads/2015/10/IPC_pipe.jpg"><img src="http://www.emacsvi.com/wp-content/uploads/2015/10/IPC_pipe-254x300.jpg" alt="IPC_pipe" width="254" height="300" class="alignnone size-medium wp-image-292" /></a>

<ol>

<li>父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端。</li>

<li>父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。</li>

<li>父进程关闭管道读端,子进程关闭管道写端。父进程可以往管道里写,子进程可以从管道里读,管道是用环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通信。</li>

</ol>

注:之前一直没明白为什么在这里父进程要关闭管道读端,并且子进程要关闭管道写端,想了很久终于想通了...,原因如下:因为上面的这个程序是要模拟父进程和子进程的管道读写操作,其中父进程用于向管道中写入数据,子进程用于向管道中读取数据,因此开始要关闭父进程的读文件描述符filedes[0], 以及关闭子进程的写文件描述符filedes[1],这是为了模拟这个过程。

然后至于为什么父进程关闭管道的读文件描述符filedes[0]后子进程还能读取管道的数据,是因为系统维护的是一个文件的文件描述符表的计数,父子进程都各自有指向相同文件的文件描述符,当关闭一个文件描述符时,相应计数减一,当这个计数减到0时,文件就被关闭,因此虽然父进程关闭了其文件描述符filedes[0],但是这个文件的文件描述符计数还没等于0,所以子进程还可以读取。也可以这么理解,父进程和子进程都有各自的文件描述符,因此虽然父进程中关闭了filedes[0],但是对子进程中的filedes[0]没有影响

文件表中的每一项都会维护一个引用计数,标识该表项被多少个文件描述符(fd)引用,在引用计数为0的时候,表项才会被删除。所以调用close(fd)关闭子进程的文件描述符,只会减少引用计数,但是不会使文件表项被清除,所以父进程依旧可以访问

最后需要注意,在linux的pipe管道下,在写端进行写数据时,不需要关闭读端的缓冲文件(即不需要读端的文件描述符计数为0),但是在读端进行读数据时必须先关闭写端的缓冲文件(即写端的文件描述符计数为0)然后才能读取数据。

<h4> manpage给的一个管道例子:</h4>
<pre lang="c" escaped="true">
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;

if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}

if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}

cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}

if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */

while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);

write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);

} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}

}
</pre>

<h4>使用管道有一些限制:</h4>
<ol>

<li> 两个进程通过一个管道只能实现单向通信,比如上面的例子,父进程写子进程读,如果有时候也需要子进程写父进程读,就必须另开一个管道。请读者思考,如果只开一个管道,但是父进程不关闭读端,子进程也不关闭写端,双方都有读端和写端,为什么不能实现双向通信?</li>

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

使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):
1. 如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
2. 如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
3. 如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。在第 33 章 信号会讲到怎样使SIGPIPE信号不终止进程。
4. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。
管道的这四种特殊情况具有普遍意义。在第 37 章 socket编程要讲的TCP socket也具有管道的这些特性。

pipe()管道最基本的IPC机制的更多相关文章

  1. Anciroid的IPC机制-Binder概述

    在Linux系统中,是以进程为单位分配和管理资源的.出于保护机制,一个进程不能直接访问另一个进程的资源,也就是说,进程之间互相封闭.但是,在一个复杂的应用系统中,通常会使用多个相关的进程来共同完成一项 ...

  2. IPC机制--Binder

    文章来自 Android技术内幕 系统卷 转:http://www.linuxidc.com/Linux/2011-08/40508.htm 什么是IPC机制以及IPC机制的种类 在Linux中,是以 ...

  3. IPC机制

    转:http://blog.chinaunix.net/uid-26125381-id-3206237.html  IPC 三种通信机制 2012-05-13 17:23:55 最近看了,IPC三种通 ...

  4. 深入理解Android IPC机制之Binder机制

    Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有的进程间通信IPC手段包括(Internet Process Connection): 管道(Pipe).信号(Sign ...

  5. 20155202 张旭 课下作业: Linux下IPC机制

    20155202张旭 Linux下IPC机制 IPC机制定义 在linux下的多个进程间的通信机制叫做IPC(Inter-Process Communication),它是多个进程之间相互沟通的一种方 ...

  6. 2017-2018-1 20155222 《信息安全系统设计基础》第10周 Linux下的IPC机制

    2017-2018-1 20155222 <信息安全系统设计基础>第10周 Linux下的IPC机制 IPC机制 在linux下的多个进程间的通信机制叫做IPC(Inter-Process ...

  7. 20155239吕宇轩 Linux下IPC机制

    20155239吕宇轩 Linux下IPC机制 - 共享内存 原理:把所有需要使用的共享数据都存放在共享内存 区域中,任何想要访问这些共享数据的进程都必须在自己的进程地址空间中新增加一块内存区域,用来 ...

  8. Linux下的IPC机制

    Linux下的IPC机制 IPC(Inter-Process Communication)是多个进程之间相互沟通的一种方法.在linux下有多种进程间通信的方法. 共享内存 Linux内存共享有多种, ...

  9. Linux下IPC机制

    Linux下IPC机制 实践要求 研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接 共享内存 管道 FIFO 信号 消息队列 IPC 进程间通信(IPC,Inter ...

随机推荐

  1. java 格式化代码 不进行换行

    此处无声胜有声.

  2. Visual Studio 项目中添加include, lib, dll库文件(*.h,*.lib,*.dll)

    应用程序使用外部库时需要进行加载,两种库的加载本质上都是一样:提供功能和功能的定义.vs2005 c++ 项目设置外部库方法如下: 1. 添加编译所需要(依赖)的 lib 文件     在“项目-&g ...

  3. ExtJs布局之Column

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  4. lintcode: 寻找旋转排序数组中的最小值

    寻找旋转排序数组中的最小值 假设一个旋转排序的数组其起始位置是未知的(比如0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2). 你需要找到其中最小的元素. 你可以假设数组中不存在重复的 ...

  5. AngularJS学习笔记1——什么是AngularJS?

    Angular JS是一个由Google维护的开源的Javascript框架,主要作者为: Misko Hevery(angular JS之父, Sr. Computer Scientist at G ...

  6. MDK5.01百度云下载,安装微软雅黑混合字体,字体效果很棒,解决显示中文的BUG

    微软雅黑字体http://pan.baidu.com/s/1nt9Epuh 初步尝试,以前的小BUG都已经解决了.下面是安装雅黑字体后的字体效果,很爽.第一步:安装雅黑字体.第二步:选择Edit--- ...

  7. WordPress定位当前使用模版

    把下面代码插入到wp-includes/template-loader.php,66行 if($_GET[tpl]=='die'){ die($template); } 浏览任意页面,在网址后加上&a ...

  8. [iOS]提交App报错ERROR ITMS -90207

    前几天上传项目N多次,都跳出这个问题 甚是头痛,于是乎各种搜索 1. 第三方的info.plist里面Executable file这个要删除(自己的不能删哦) 2.检查一下用来做跳转到第三方应用的设 ...

  9. CentOS下判断自己的VPS是OpenVZ的还是Xen的

    一般来说,VPS的虚拟化技术,有Xen.OpenVZ.Xen HVM和VMware这几种,那么,如何判断自己的VPS是基于哪种虚拟化技术的呢? 1.执行:ls /proc/命令,一般Xen的VPS,/ ...

  10. JVM内存区域划分

    前言 Java程序的运行是通过Java虚拟机来实现的.通过类加载器将class字节码文件加载进JVM,然后根据预定的规则执行.Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同 ...