在实际开发过程中,程序员必须让拥有依赖关系的进程集协调,这样才能达到进程的共同目标。 
  每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程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[2];char str[1024] = "hello it is a test\n";char buf[1024] = {0};pid_t pid;//fd[0]读端//fd[1]写端if(pipe(fd) < 0){perror("pipe");exit(1);}pid = fork();if(pid > 0){//父进程里,关闭父读close(fd[0]);sleep(3);//通过这个sleep可以知道管道的读是一个堵塞函数write(fd[1], str, strlen(str));//当管道满的时候,再写就会阻塞
        wait(NULL);close(fd[1]);//用完管道要关闭读端和写端
    }else if(pid == 0){int len = 0;//子进程里,关闭子写close(fd[1]);len = read(fd[0], buf, sizeof(buf));write(STDOUT_FILENO, buf, len);close(fd[0]);//用完管道要关闭读端和写端
    }else{perror("fork");exit(1);}return 0;
}运行结果:
运行后过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[2];char str[1024] = "hello it is a test\n";char buf[1024] = {0};pid_t pid;//fd[0]读端//fd[1]写端if(pipe(fd) < 0){perror("pipe");exit(1);}pid = fork();if(pid > 0){//父进程里,关闭父读close(fd[0]);sleep(5);write(fd[1], str, strlen(str));//当管道满的时候,再写就会阻塞
        wait(NULL);close(fd[1]);//用完管道要关闭读端和写端
    }else if(pid == 0){int len = 0, flags;//子进程里,关闭子写close(fd[1]);//使其非阻塞---------------------------------------flags = fcntl(fd[0],F_GETFL);flags |= O_NONBLOCK;fcntl(fd[0],F_SETFL,flags);while(1){len = read(fd[0], buf, sizeof(buf));if(len == -1){perror("read");}else{write(STDOUT_FILENO, buf, len);break;}sleep(1);}close(fd[0]);//用完管道要关闭读端和写端
    }else{perror("fork");exit(1);}return 0;
}运行结果:
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

转载于:https://www.cnblogs.com/13224ACMer/p/6390351.html

linux 进程间通信之pipe相关推荐

  1. #Linux#进程间通信# 管道(pipe)-标准流管道pipe

    在#Linux#进程间通信# 管道(pipe)-普通管道pipe中,我们很容易可以看出普通管道一是单工,即只能单向传输,而标准流管道针对匿名管道PIPE一系列封装.返回文件流.只不过返回的文件流无法使 ...

  2. #Linux#进程间通信# 管道(pipe)-匿名管道pipe

    我们通常把一个进程连接到另一个进程的一个数据流称为一个"管道",通常是用作把一个进程的输出通过管道连接到另一个进程的输入.管道本质上是内核的一块缓存.内核使用环形队列机制,借助内核 ...

  3. Linux进程间通信分类 以及 pipe的原理实现

    http://blog.sina.com.cn/s/blog_4a84bd960100by8s.html http://home.lupaworld.com/home-space-uid-296848 ...

  4. linux进程间通信:POSIX 共享内存

    文章目录 思维导图 通信原理 优势 POSIX 共享内存 编程接口 编程案例 思维导图 之前学习过sysemV 的共享内存的实现及使用原理,参考linux进程间通信:system V 共享内存 POS ...

  5. Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存

    Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> ...

  6. 20155301 滕树晨linux基础——linux进程间通信(IPC)机制总结

    20155301 滕树晨linux基础--linux进程间通信(IPC)机制总结 共享内存 共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在 ...

  7. Linux 进程间通信

    引言 进程通信的目的: 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一 ...

  8. Linux进程间通信——管道

    转自:http://www.cnblogs.com/feisky/archive/2010/03/24/1693484.html Linux进程间通信机制: 1.同一主机进程间通信机制: Unix方式 ...

  9. Linux进程间通信(管道、消息队列、共享内存、信号、信号量)

    目录 Linux进程间通信概述 1.管道 无名管道(pipe) 有名管道(fifo) 2.消息队列(msg) 消息队列的通信原理 消息队列相关api 消息队列收发数据 键值生成 消息队列移除 3.共享 ...

最新文章

  1. html靶心制作,用PS单色填充制作一个靶心
  2. Shell编程—【01】shell中常用的字符串操作
  3. 网络营销过程中如何避免网站的过度优化情况的发生?
  4. c语言随机产生100个字母,C语言实现产生100以内的随机数做加减运算
  5. 教师计算机应用测试题,教师计算机等级考试模拟考试题演示教学
  6. 深度学习(参数选择)
  7. 微型计算机系统中 麦克风属于,模块1-2 计算机基础知识测验题目(50小题)
  8. 好程序员Java教程分享使用HttpClient抓取页面内容
  9. D1、4CIF、CIF和QCIF的不同
  10. 通用型二阶卡尔曼滤波算法
  11. Python百行代码随机生成姓名
  12. 如何裁剪动态图片?教你三步快速裁剪GIF
  13. 什么是数据运营?数据运营是做什么的?
  14. Linux命令任务管理器,如何在:Linux下面启动任务管理器
  15. Windows如何安装Clouda
  16. python输入名字配对情侣网名_名字匹配度情侣,打出自己的名字和对象的名字
  17. [book]《岩田先生》
  18. mysql查询使用qq邮箱注册_Spring Boot实现qq邮箱验证码注册和登录验证功能
  19. Matplotlib、PIL Image如何将多张图片整合保存为一张图片
  20. 身为编辑者,居然无法提交申请?

热门文章

  1. Java中集合(六)Queue
  2. 【嵌入式】ARM技术博客汇总
  3. 【STM32】ST-LINK固件升级
  4. 【ARM】Tiny4412裸板编程之Chip ID
  5. c# 接收网络汉字乱码_50种网络故障及解决方法
  6. mysql子查询是什么_mysql子查询
  7. 多进程 fork()与vfork()
  8. 手把手教你在windows10下进行openFoam调试
  9. sparksql(2)——dataframe的ap-printSchema、withColum、count、drop、describe、select
  10. 机器学习 KD树生成(matlab实现)