在实际开发过程中,程序员必须让拥有依赖关系的进程集协调,这样才能达到进程的共同目标。 
  每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程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. git 指定用户名密码更新代码

    使用git 更新代码 如何修改git 的密码一直令人费解,百度一堆也没给出答案.下面给一种替代方案. 例如:我们正常的代码地址 http://172.16.210.112/project/test.g ...

  2. 打造开源GIS方案

    现在GIS用途较多,最近要有所接触,所以决定自己打造一个已经又的方案.均以Java作为开发 二位地图:客户端:geotools,swing,geoserver; web:openlayer,geose ...

  3. C.Sum 2017 ACM-ICPC 亚洲区(西安赛区)网络赛

    题目来源:Sum 限制:1000ms 32768K Define the function S(x) for xx is a positive integer. S(x) equals to the ...

  4. 【TOJ 1449】Area of Circles II(求不同位置的两圆面积之和)

    描述 There are two circles on the plane. Now you must to calculate the area which they cover the plane ...

  5. 在cmd下面执行.py文件时提示ModuleNotFoundError 但是 IDE 不报错

    原理是 python 解释器寻找 模块的顺序决定,不细说 简略来讲就是 在 IDE中运行,会自动帮你把项目根目录添加到 PYTHONPATH 中,但是在 cmd 运行需要自己添加. 解决方法: 1. ...

  6. 【赛时总结】NOIP2018-三校联考1024

    ◇NOIP三校联考-1024◇ 发现以前的博客写得似乎都很水……基本上都没什么阅读量QwQ 决定改过自新╰( ̄ω ̄o) 就从这篇博客开始吧~ 现场考得无地自容,看到题解才发现一些东西……(我第三题还没 ...

  7. 增删改查 报异常org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readO

    可能是Spring配置文件 事务通知里面的方法  与实际方法不匹配 <tx:advice id="advice" transaction-manager="tran ...

  8. SQL:检索数据-基本检索

    检索数据 1.select语句 增删改查四大操作之"查",即检索: 一般包括:what,where:查什么,从哪里选择 2.检索单个列 例:想从products表中检索名为prod ...

  9. CacheCloud+Redis Cluster 3部署

    CacheCloud环境需求 Java 7 Maven 3 MySQL Redis 3 具体用法可参考:https://cachecloud.github.io 1.下载CacheCloud 官网ht ...

  10. tp3.2报错;syntax error, unexpected 'function' (T_FUNCTION), expecting identifier (T_STRING) or \\ (T_NS_SEPARATOR)

    出错原因:这个是php版本问题,laravel5.1的php版本要求是PHP >= 5.5.9,切换一下PHP版本就行.