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

    Oracle使用EXPDP和IMPDP数据泵进行导出导入的方法(常用方法) 使用expdp和impdp时应该注重的事项: 1.exp和imp是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用 ...

  2. Java的内存--存储(1)

    有次去面试,面试官突然问我这个问题,当时我只知道怎么写最优化,但是具体不知道为什么那样写,身价立马下降哦 1. 以下开发习惯,你怎么看? for(int i=0;i<2;i++){ Person ...

  3. SAC E#1 - 一道难题 Tree(树形DP)

    题目背景 冴月麟和魏潇承是好朋友. 题目描述 冴月麟为了守护幻想乡,而制造了幻想乡的倒影,将真实的幻想乡封印了.任何人都无法进入真实的幻想乡了,但是她给前来救她的魏潇承留了一个线索. 她设置了一棵树( ...

  4. 【2018 ICPC焦作网络赛 G】Give Candies(费马小定理+快速幂取模)

    There are N children in kindergarten. Miss Li bought them N candies. To make the process more intere ...

  5. MySQL备份恢复之Xtrabackup

    Preface       Today,I'm gonna use the Xtrabackup tool to demonstrate the procedure of backing up MyS ...

  6. 路由器基础配置之ospf基础配置

    我们将以上面的拓扑图进行本次ospf的实验,目的是能当三台pc机互通 先配置好pc机的IP地址,注意一定要给pc机设置好网关,接下来配置路由器的IP地址 router4 enable 进入特权模式 c ...

  7. 关于使用array_rand随机取出数组的值

    代码如下 <?php echo "<meta charset='utf-8'/>";//选择解码方式,防止乱码现象 $a = array("abc&qu ...

  8. linux 用户 用户组

    useradd -m -G sudo zhangxiao passwd zhangxiao

  9. python字符串,数组操作

    今天倒是学到了很多知识,了解了python的基本数组,以及可变类型和不可变类型,还有元组,列表,字典等等的用法 然后作业如下 其中在做往list列表加东西时候遇到了小毛病,用户从控制台输入的是一个字符 ...

  10. 第一个网页(仿照当当网,仅仅使用CSS)

    这个网页是在学过CSS之后,对当当网首页进行模仿的网页,没有看当当网的网页源码,纯按照自己之前学的写的,由于是刚学过HTML和CSS才一个星期,所以里面有许多地方写的非常没有水平,仅仅用来学习使用,欢 ...