进程间通信

  • 1.进程间通信概念及方式
  • 2.管道
    • 2.1 管道概念
    • 2.2 管道的原理
    • 2.3 管道的局限性
    • 2.4 管道的优缺点
  • 3.管道创建与应用
    • 3.1 pipe函数创建并打开
    • 3.2 程序实现
    • 3.3 管道的读写行为
      • 3.3.1 读管道
      • 3.3.2 写管道
      • 3.3.3 程序实例1
      • 3.3.4 程序实例2
  • 4.管道缓冲区大小
  • 5.命名管道FIFO
  • 6.命名管道与匿名管道的区别
  • 参考

1.进程间通信概念及方式

  ​linux系统下,进程空间地址相互独立,每个进程各自有不同的用户地址。任何一个进程的全局变量在另有一个进程中都看不到,所以进程和进程间不能互相访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1的数据从用户空间拷贝至内核缓冲区,进程2再从缓冲区把数据读取,内核提供的这种机制称为进程间通信(IPC)。


​  在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。

​  主要方式有:

​     ① 管道 (使用最简单)

​     ② 信号 (开销最小)

​     ③ 共享映射区 (无血缘关系)

​     ④ 本地套接字 (最稳定)

  本文以下内容主要针对的是管道进行展开,其它进程间通信方式将在以后的文章中讲解。

2.管道

2.1 管道概念

​  管道是一种最基本的 IPC 机制,作用于有血缘关系进程之间,完成数据传递。调用 pipe 系统函数(或者用mkfifo命令)即可创建一个管道。有如下特质:

  1. 其本质是一个伪文件(实为内核缓冲区)

  2. 由两个文件描述符引用,一个表示读端,一个表示写端。

  3. 规定数据从管道的写端流入管道,从读端流出。

2.2 管道的原理

  管道实为内核使用环形队列机制(FIFO),借助内核缓冲区(4k)实现。

2.3 管道的局限性

​   1. 数据不能进程自己写,自己读。

​   2. 管道中数据不可反复读取。一旦读走,管道中不再存在。

​   3. 采用半双工通信方式,数据只能在单方向上流动。

   4.只能在有公共祖先的进程间使用管道。

2.4 管道的优缺点

优点:

  简单,相比信号,套接字实现进程间通信,简单很多。

缺点:

  1. 只能单向通信,双向通信需建立两个管道。

  2. 只能用于父子、兄弟进程(有共同祖先)间通信。该问题后来使用 fifo 有名管道解决。

3.管道创建与应用

3.1 pipe函数创建并打开

函数原型:

int pipe(int pipefd[2]);

参数:
  fd[0] : r 读端

  fd[1] : w 写端

返回值:

  成功:0;失败:-1,设置 errno

注:函数调用成功返回 r/w 两个文件描述符。无需 open,但需手动 close。

  管道创建成功以后,创建该管道的进程(父进程)同时掌握着管道的读端和写端。实现父子进程间通信通常可以采用如下步骤:

3.2 程序实现

int main (int argc,char *argv[])
{int ret;int fd[2];char buf [1024];pid_t pid;ret =pipe(fd);if(ret==-1){sys_err("pipe error");}pid =fork();if(pid>0){   //父进程写  父进程关闭管道读端close(fd[0]);write((fd[1]),"hello pipe",strlen("hello pipe"));sleep(1);close(fd[1]);}else if (pid ==0){//子进程读   子进程关闭管道写端close(fd[1]);ret=read(fd[0],buf,sizeof(buf));write(STDOUT_FILENO,buf,ret);close(fd[0]);}return 0;
}

3.3 管道的读写行为

3.3.1 读管道

  1. 管道中有数据,read 返回实际读到的字节数。

  2. 管道中无数据:

    (1) 管道写端被全部关闭,read 返回 0 (好像读到 文件结尾

    (2) 写端没有全部被关闭,read 阻塞等待(不久的 将来可能有数据递达,此时会让出 cpu)

3.3.2 写管道

  1. 管道读端全部被关闭, 进程异常终止(也可使用捕捉 SIGPIPE 信号,使进程不终止)

  2. 管道读端没有全部关闭:

    (1) 管道已满,write 阻塞。

    (2) 管道未满,write 将数据写入,并返回实际写入的字节数。

3.3.3 程序实例1

  使用管道实现父子进程间通信,完成:ls | wc –l。假定父进程实现 ls,子进程实现 wc。ls 命令正常会将结果集写出到 stdout,但现在会写入管道的写端;wc –l 正常应该从 stdin 读取数据,但此时会从管道的读端读。

代码:

#include<iostream>
#include<stdlib.h>
#include<unistd.h>
#include <sys/wait.h>
#include <string.h>
using namespace std;
void sys_err(const char *str)
{perror(str);exit(1);
}
int main (int argc,char *argv[])
{int ret;int fd[2];char buf [1024];pid_t pid;//创建管道ret =pipe(fd);//判断是否创建成功if(ret==-1){sys_err("pipe error");}//创建子进程pid=fork();if(pid==-1)//创建子进程失败{perror("fork error");exit(1);}//实现从父进程向子进程通信,父进程写管道打开,读管道关闭; 子进程读管道打开,写管道关闭else if(pid>0)//父进程{//父进程关闭读端close(fd[0]);//将标准输出文件描述符指向父进程管道写端dup2(fd[1],STDOUT_FILENO);//利用execlp函数执行指定程序命令execlp("ls","ls",NULL) ;}else if (pid==0)//子进程{//子进程关闭写端close(fd[1]);//将标准输入文件描述符指向子进程管道读端dup2(fd[0],STDIN_FILENO);//利用execlp函数执行指定程序命令execlp("wc","wc","-l",NULL);}return 0;
}

运行结果:

3.3.4 程序实例2

  使用管道实现兄弟进程间通信。 兄:ls 弟: wc -l 父:等待回收子进程。

  要求:使用“循环创建 N 个子进程”模型创建兄弟进程,使用循环因子 i 标示。注意管道读写行为。

代码:

#include<iostream>
#include<stdlib.h>
#include<unistd.h>
#include <sys/wait.h>
#include <string.h>
using namespace std;
void sys_err(const char *str)
{perror(str);exit(1);
}int main (int argc,char *argv[])
{int i,ret;int fd[2];char buf [1024];pid_t pid;//创建管道ret =pipe(fd);//判断是否创建成功if(ret==-1){sys_err("pipe error");}//创建子进程   循环创建for(i=0;i<2;i++)   //表达式2出口   父进程使用{pid =fork();if(pid==-1)//创建子进程失败{perror("fork error");exit(1);}if (pid==0)  //子进程出口break;}if(i==2)//父进程{close(fd[0]);close(fd[1]);wait (NULL);wait (NULL);}else if (i==0)//兄进程{close(fd[0]);//将标准输出文件描述符指向兄进程管道写端dup2(fd[1],STDOUT_FILENO);//利用execlp函数执行指定程序命令execlp("ls","ls",NULL) ;}else if (i==1)//弟进程{close(fd[1]);//将标准输入文件描述符指向弟进程管道读端dup2(fd[0],STDIN_FILENO);//利用execlp函数执行指定程序命令execlp("wc","wc","-l",NULL);}return 0;
}

运行结果:

4.管道缓冲区大小

  可以使用 ulimit –a 命令来查看当前系统中创建管道文件所对应的内核缓冲区大小。通常为:

pipe size (512 bytes, -p) 8

  也可以使用 fpathconf 函数,借助参数 选项来查看。使用该宏应引入头文件

<unistd.h>long fpathconf(int fd, int name);

成功:返回管道的大小

失败:-1,设置 errno

5.命名管道FIFO

  FIFO 常被称为命名管道,以区分管道(pipe)。管道(pipe)只能用于“有血缘关系”的进程间。但通过 FIFO,不相关的进程也能交换数据。

  FIFO 是 Linux 基础文件类型中的一种。但FIFO 文件在磁盘上没有数据块,仅仅用来标识内核中一条通道。各进程可以打开这个文件进行 read/write,实际上是在读写内核通道,这样就实现了进程间通信。

创建:

  1. ​命令行:mkfifo 管道名

  2. 库函数:int mkfifo(const char *pathname, mode_t mode); 成功:0; 失败:-1

6.命名管道与匿名管道的区别

  1. 在通信上,命名管道提供了一个路径名与之关联,以FIFO文件的形式存储于文件系统中,能够实现任何两个进程之间通信。而匿名管道对于文件系统是不可见的,它仅限于在父子进程之间的通信。原因在于:匿名管道内核中的缓冲区没有标识符,(没有管道标识符)所以其他进程无法使用。而命名管道内核中的缓冲区有标识符
  2. 在使用上,命名管道创建完成后就可以使用,其使用方法与管道一样,区别在于:命名管道使用之前需要使用open()打开。这是因为:命名管道是设备文件,它是存储在硬盘上的,而管道是存在内存中的特殊文件。但是需要注意的是,命名管道调用open()打开有可能会阻塞,但是如果以读写方式(O_RDWR)打开则一定不会阻塞;以只读(O_RDONLY)方式打开时,调用open()的函数会被阻塞直到有数据可读;如果以只写方式(O_WRONLY)打开时同样也会被阻塞,知道有以读方式打开该管道。

参考

https://blog.csdn.net/qq_33951180/article/details/68959819

进程间通信方式——管道相关推荐

  1. IPC 进程间通信方式——管道

    进程间通信概述 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到. 通知时间: ...

  2. linux下进程间管道通信,Linux下进程间通信方式-管道

    本文关键字: linux 管道通信,linux 进程通信方式,无名管道,有名管道 管道是Linux中进程间通信的一种方式,它把一个程序的输出直接连接到另一个程序的输入.Linux的管道主要包括两种:无 ...

  3. [【转载】 linux进程间通信方式

    目录 目录 进程通信的目的 Linux 进程间通信(IPC)的发展 linux使用的进程间通信方式 管道( pipe ) 信号量( semophore ) 消息队列( message queue ) ...

  4. 一种网络进程间通信的方式—— 管道

    一种网络进程间通信的方式-- 管道 摘要: 文章主要介绍了计算机网络进程间通信的必要性以及进程间通信所采用的几种方式,重点说明了管道通信的原理及命名管道的实现方法. 关键词:管道 命名管道 进程 一. ...

  5. 进程间通信方式(一)-- 无名管道、有名管道

    文章目录 1. 进程间通信方式分类 2. 进程间通信实现方式 3. 无名管道 3.1 概念 3.2 相关函数 读写规律 3.3 无名管道实现进程间通信 4. 有名管道 4.1 概念 4.2 创建有名管 ...

  6. dat关闭某进程_超详细解析!工程师必会的Linux进程间通信方式和原理

    ▍进程的概念 · 进程是操作系统的概念,每当我们执行一个程序时,对于操作系统来讲就创建了一个进程,在这个过程中,伴随着资源的分配和释放.可以认为进程是一个程序的一次执行过程. ▍进程通信的概念 · 进 ...

  7. linux内核剖析(八)进程间通信之-管道

    管道 管道是一种两个进程间进行单向通信的机制. 因为管道传递数据的单向性,管道又称为半双工管道. 管道的这一特点决定了器使用的局限性.管道是Linux支持的最初Unix IPC形式之一,具有以下特点: ...

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

    进程间通信 管道 共享内存 消息队列 信号量 进程间通信 https://blog.csdn.net/qq_35423154/article/details/105294963 在之前的一篇博客中讲过 ...

  9. 两个不同的进程 虚拟地址相同_记一次阿里面试题:都有哪些进程间通信方式?麻烦你不要再背了...

    1 管道 学习软件工程规范的时候,我们知道瀑布模型,在整个项目开发过程分为多个阶段,上一阶段的输出作为下一阶段的输入.各个阶段的具体内容如下图所示 最初我们在学习Linux基本命令使用的时候,我们经常 ...

最新文章

  1. JavaScript和HTML实现的简单计算机
  2. [推荐]数据库索引碎片的自动重建或重组
  3. Spark - 大数据Big Data处理框架
  4. AI部署前路坎坷,50%项目半路夭折
  5. 关于struts,spring,hibernate的几个问题
  6. HDU - 4348 To the moon(主席树区间更新-标记永久化)
  7. 聊一聊ws2_32.dll和wsock32.dll
  8. Apache Ignite,Hazelcast,Cassandra和Tarantool之间的主要区别
  9. 美国虚拟主机大打安全牌争抢国内高端外贸主机市场
  10. HDU1850 Being a Good Boy in Spring Festival
  11. SPSS计算变量(图文+数据集)【SPSS 012期】
  12. 计算机程序设计语言分为机器语言,汇编语言和高级语言三种,简述计算机程序设计语言(机器语言、汇编语言、高级语言)的优缺点。...
  13. 配置WindowsMobile仿真器上网
  14. 如何使用计算机远程关闭手机软件,如何用手机远程控制电脑关机
  15. 常用的vim命令,主要是写给宝贝儿方便工作查看的
  16. 大话拒绝服务攻击:DoS、DDoS、LDoS——“直男、舔狗和渣男”
  17. 34-高级路由:BGP汇总:实验五 route-map+suppress-map过滤、as-set
  18. Android12 (S) 获取wifi名称(SSID)的方法
  19. 2022年最新遥感类期刊JCR影响因子及分区
  20. cdma特有效应_CDMA技术基础知识

热门文章

  1. 图片怎么批量重命名?掌握这招轻松处理
  2. 管家婆分销ERP V3、A8错误提示“操作必须使用一个可更新的查询”
  3. java 复杂报表_复杂Java报表解决方案|思达Java报表软件Style Report
  4. c语言队列程序怎么写,[原创]非常漂亮的队列演示程序(C语言版)
  5. php的未来发展,关于PHP未来发展的N个严肃思考
  6. 关于Echarts柱状图点击事件的实现方法charsjs柱状图点击事件
  7. java poi 加粗居中_poi生成excel整理(设置边框/字体/颜色/加粗/居中/)
  8. Linux运维发展方向
  9. amcharts_flash_1.6(绝版了)破解说明
  10. 健康医疗大数据应用发展的指导意见