在实际开发过程中,程序员必须让拥有依赖关系的进程集协调,这样才能达到进程的共同目标。 
  每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。


  管道是一种最基本的IPC机制,由pipe函数创建:

#include <unistd.h>
  
int pipe(int filedes[2]);

  管道作用于有血缘关系的进程之间,即通过fork所创建的进程。

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

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h> int main(void)
{
int fd[];
char str[] = "hello it is a test\n";
char buf[] = {};
pid_t pid; //fd[0]读端
//fd[1]写端
if(pipe(fd) < )
{
perror("pipe");
exit();
} pid = fork();
if(pid > )
{
//父进程里,关闭父读
close(fd[]);
sleep();//通过这个sleep可以知道管道的读是一个堵塞函数
write(fd[], str, strlen(str));//当管道满的时候,再写就会阻塞
wait(NULL); close(fd[]);//用完管道要关闭读端和写端
}
else if(pid == )
{
int len = ;
//子进程里,关闭子写
close(fd[]);
len = read(fd[], buf, sizeof(buf));
write(STDOUT_FILENO, buf, len); close(fd[]);//用完管道要关闭读端和写端
}
else
{
perror("fork");
exit();
} return ;
} 运行结果:
运行后过3秒输出 hello it is a test

 所以使用管道会有一些限制: 
  两个进程通过一个管道只能实现单向通信,比如上面的例子,父进程写子进程读,如果有时候也需要子进程写父进程读,就必须另开一个管道。 
  管道的读写端通过打开的文件描述符来传递,因此要通信的两个进程必须从它们的公共祖先那里继承管道文件描述符。上面的例子是父进程把文件描述符传给子进程之后父子进程之间通信,也可以父进程fork两次,把文件描述符传给两个子进程,然后两个子进程之间通信,总之需要通过fork传递文件描述符使两个进程都能访问同一管道,它们才能通信


  使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):

  1. 如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
  2. 如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
  3. 如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止
  4. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。

以上情况具有普遍性,设计的时候需要注意。

管道的局限性

管道的主要局限性正体现在它的特点上:

  • 只支持单向数据流;
  • 只能用于具有亲缘关系的进程之间;
  • 没有名字;
  • 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);
  • 管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;

注:阻塞管道, 使用fcntl函数设置O_NONBLOCK标志(fcntl的使用方法 
举例:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h> int main(void)
{
int fd[];
char str[] = "hello it is a test\n";
char buf[] = {};
pid_t pid; //fd[0]读端
//fd[1]写端
if(pipe(fd) < )
{
perror("pipe");
exit();
} pid = fork();
if(pid > )
{
//父进程里,关闭父读
close(fd[]);
sleep();
write(fd[], str, strlen(str));//当管道满的时候,再写就会阻塞
wait(NULL);
close(fd[]);//用完管道要关闭读端和写端
}
else if(pid == )
{
int len = , flags;
//子进程里,关闭子写
close(fd[]); //使其非阻塞---------------------------------------
flags = fcntl(fd[],F_GETFL);
flags |= O_NONBLOCK;
fcntl(fd[],F_SETFL,flags); while()
{
len = read(fd[], buf, sizeof(buf));
if(len == -)
{
perror("read");
}
else
{
write(STDOUT_FILENO, buf, len);
break;
}
sleep();
}
close(fd[]);//用完管道要关闭读端和写端
}
else
{
perror("fork");
exit();
} return ;
} 运行结果:
read: Resource temporarily unavailable
read: Resource temporarily unavailable
read: Resource temporarily unavailable
read: Resource temporarily unavailable
read: Resource temporarily unavailable
hello it is a test

linux 进程间通信之pipe的更多相关文章

  1. Linux进程间通信 -- 管道(pipe)

    前言    进程是一个独立的资源管理单元,不同进程间的资源是独立的,不能在一个进程中访问另一个进程的用户空间和内存空间.但是,进程不是孤立的,不同进程之间需要信息的交互和状态的传递,因此需要进程间数据 ...

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

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

  3. 练习--LINUX进程间通信之无名管道PIPE

    IBM上放的这个系统不错,刚好可以系统回温一下LINUX的系统知识. http://www.ibm.com/developerworks/cn/linux/l-ipc/part1/ 感觉年纪大了,前几 ...

  4. c/c++ linux 进程间通信系列3,使用socketpair,pipe

    linux 进程间通信系列3,使用socketpair,pipe 1,使用socketpair,实现进程间通信,是双向的. 2,使用pipe,实现进程间通信 使用pipe关键点:fd[0]只能用于接收 ...

  5. Linux进程间通信(四):命名管道 mkfifo()、open()、read()、close()

    在前一篇文章—— Linux进程间通信 -- 使用匿名管道 中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关 ...

  6. Linux 进程间通信(二) 管道

    Linux 进程间通信-管道 进程是一个独立的资源分配单位,不同进程之间的资源是相互独立的,没有关联,不能在一个进程中直接访问另一个进程中的资源.但是,进程不是孤立的,不同的进程之间需要信息的交换以及 ...

  7. 【转】 Linux进程间通信

    一.进程间通信概述进程通信有如下一些目的:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别 ...

  8. Linux进程间通信(IPC)

    序言 linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的. 而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心) ...

  9. Linux进程间通信——使用匿名管道

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

随机推荐

  1. MySQL配置和启动

    1.首先下载MySQl安装包,解压安装包 打开mysql下面的bin文件夹,双击如图标记的  .exe运行 2.配置Mysql (1)运行程序后点击 next (2)这里有精确配置和标准配置,根据情况 ...

  2. mysql忘记密码重置

    一.更改my.cnf配置文件 0.MySQL 版本查看 mysql --version 1.用命令编辑/etc/my.cnf配置文件,即:vim /etc/my.cnf 或者 vi /etc/my.c ...

  3. Largest Rectangle in a Histogram(hdu1506,单调栈裸题)

    Largest Rectangle in a Histogram Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  4. datatable根据条件设置表格行中字的颜色或背景

    使用row回调函数 "rowCallback": function (row, data) { if (xxx) { //给行添加背景色 $(row).css("back ...

  5. JQuery中使用FormData异步提交数据和提交文件

    web中数据提交事件是常常发生的,但是大多数情况下我们不希望使用html中的form表单提交,因为form表单提交会中断当前浏览器的操作并且会调到另一个地址(即使这个地址是当前页面),并且会重复加载一 ...

  6. Java : 多态表现:静态绑定与动态绑定(向上转型的运行机制)

    本来想自己写写的,但是看到有人分析的可以说是很清晰了,故转过来. 原文地址:http://www.cnblogs.com/ygj0930/p/6554103.html 一:绑定 把一个方法与其所在的类 ...

  7. ruby 数据类型Number

    Ruby支持的数据类型包括基本的Number.String.Ranges.Symbols,以及true.false和nil这几个特殊值,同时还有两种重要的数据结构——Array和Hash 数值类型(N ...

  8. ffplay使用笔记

    ffplay播放yuv文件命令: ffplay -f rawvideo -video_size 1920x1080 a.yuv   ffplay播放mp4.h.264.hevc文件命令: ffplay ...

  9. (数据科学学习手札01)Python与R基本数据结构之异同

    Python 1.列表(list) list1 = [i for i in range(10)] list1[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 特点:可遍历,可索引,可切片 ...

  10. css在线sprite

    大家知道网站图片多,浏览器下载多个图片要有多个请求.可是请求比较耗时,那怎么办呢? 对,方法就是css sprite. 今天我们来看看css在线sprite 百度搜索css-sprite 打开www. ...