Linux IPC之管道通信
2017-04-07
管道通信在linux中使用较为频繁的进程通信机制。基于unix一切皆文件的传统,管道也是一种文件。所以可以使用一般的VFS接口对管道进行读写操作,如read、write。具体管道分为有名管道和无名管道。无名管道的使用场景较为局限,仅仅限制在有亲缘关系的进程之间通信,多由于父子进程。而有名管道使用就广泛一些,可以在任何有权限的进程之间进行通讯。而这正是有其本质的实现机制所导致的。
一、无名管道
在linux中,管道的实现没有具体的数据结构,而是借助了文件系统的file结构和VFS的inode节点,在之前的文件系统章节介绍过,file结构代表进程打开的一个文件,记录着关于本次打开这个文件的动态信息,是局部于进程的。通过将两个file结构指向同一个inode节点,inode节点又指向一个物理页面,实现两个通过两个文件描述符操作同一文件。关于具体文件系统的知识这里不赘述,感兴趣可以参考之前的博文。正如前面所述,文件描述符不是通过open系统调用打开具体的文件获得,而是通过pipe直接通过内核创建的,所以其他进程无法获取文件描述符也就无法使用其进行通信。这在一定程度上保证了通信的安全,但是也限制了其应用场景。
管道的读写函数是pipe_read和pipe_write函数,管道写函数通过将字节复制到inode节点指向的物理内存而写入数据,而管道读函数通过复制物理内存中的字节而读出数据。既然涉及到两个进程操作同一资源,就避免不了使用同步机制,为此,内核使用了锁,等待队列和信号机制。当写进程向管道写入数据时,利用标准库函数write(),系统根据库函数传递的文件描述符,找到文件的file结构,(文件描述符其实是file数组中的索引),根据file结构找到inode节点,在正式写入数据时,必须检查节点中的信息,在满足如下条件时,才能进行实际的复制工作。
- 内存中有足够的空间可容纳所要写入的数据。
- 内存中没有被读程序锁定。
如果满足条件,写函数要先锁定内存,防止读进程干扰,然后从写进程地址空间复制数据到内存。如果不满足,写进程就休眠在节点的等待队列中,而休眠函数会触发内核调度。当条件满足时,读取进程会唤醒写入进程,写入进程收到信号,重新挂入就绪队列,待再次被调度就可以执行写操作。写入完成后,释放锁,此时所有休眠在该节点的读取进程会被唤醒,因为读操作并不是排他的。
管道的读取过程和写入过程类似,这里就不在重复。默认情况下,当管道为空时,读进程会阻塞;而在管道空间不足时,写进程会阻塞。当然,这是可以设置的,具体见fcntl()函数的介绍。
二、有名管道
前面已经介绍到无名管道的局限性,在看无名管道的时候我也在想,为何不直接通过一个磁盘文件来通信,这样还可以任意进程之间的通信,难道当初就是为了避免这样,才设计的无名管道??
和无名管道相反,有名管道真真实实的有名字,即它在磁盘上有自己对应的文件,所以不同的进程也可以通过打开该文件,对其进行读写。这正是克服了无名管道仅用于亲缘进程之间通信的缺点。有名管道的操作方式基于先进先出的原理,所以有称有名管道为FIFO。通过mknod函数可以创建FIFO文件,该文件一旦创建成功,任何具备权限的进程都可以对其执行打开操作,进而发生读写。只是当多个进程操作文件时,也需要同步机制的保障。
三、管道通信面临的问题
1、缓冲区的限制
2、读写速度不一致
由于不管是有名管道和无名管道都不能像普通文件那样任意扩展空间,其通信的数据量就受到限制,linux下缓冲区的大小为1页面即4kb,所以管道比较适合数据量不大的进程通信。而面对读写速度不一致的问题,读进程只能通过阻塞自己来等待,一定程度上也会影响管道通信的效率。
参考资料:
1、《深入分析linux内核源码》
Linux IPC之管道通信的更多相关文章
- linux进程的管道通信
linux进程的管道通信 要求 编程实现进程的管道通信,掌握管道通信的同步和互斥机制. 相关函数 pipe管道 指用于连接一个读进程和一个写进程以实现他们之间通信的一个共享文件,又名pipe文件.向管 ...
- linux IPC总结——管道
管道 管道是unix ipc的最古老形式,是一种在内存中的特殊文件,只能在具有公共祖先的进程之间使用(即父子进程,兄弟进程). 管道由pipe函数创建 #include <unistd.h> ...
- linux 管道通信
下面举linux下有名管道通信的代码. ----------------------------------------- fifo_read.c =========== #include<er ...
- windows10使用VS(VC++)创建c++多进程命名管道通信
代码可以在 这里 下载 代码主要涉及到: 管道通信 多线程(含临界区) 多进程通信 创建的子进程独立运行 更新日志: 04-12-2020 1. 去除自定义函数返回值,改为int作为函数返回值并增加相 ...
- Linux下进程间管道通信小作业
在进行这次作业之前,我们先来看看什么是管道吧! 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间, ...
- Linux学习记录--命名管道通信
命名管道通信 什么是命名管道 一个主要的限制是,它是匿名管道的应用还没有名字,因此,只有它可以用于进程间通信的方式与亲缘关系.在命名管道(named pipe或FIFO)提出后,该限制得到了克服.FI ...
- linux进程篇 (三) 进程间的通信1 管道通信
通信方式分4大类: 管道通信:无名管道 有名管道 信号通信:发送 接收 和 处理 IPC通信:共享内存 消息队列 信号灯 socke 网络通信 用户空间 进程A <----无法通信----> ...
- linux下的进程通信之管道与FIFO
概念:管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息. 优点:不需 ...
- Linux无名管道通信介绍
Linux下无名管道一般仅用于父子进程间的通信: 测试代码如下 //file name: fifo_test.c #include <sys/prctl.h> #include " ...
随机推荐
- Hive入门笔记---2.hive函数大全
Hive函数大全–完整版 现在虽然有很多SQL ON Hadoop的解决方案,像Spark SQL.Impala.Presto等等,但就目前来看,在基于Hadoop的大数据分析平台.数据仓库中,Hiv ...
- Farey Sequence(欧拉函数)
题意:给出式子F F中分子分母互质,且分子小于分母 例: F2 = {1/2} F3 = {1/3, 1/2, 2/3} F4 = {1/4, 1/3, 1/2, 2/3, 3/4} F5 = {1/ ...
- BI开发之——Mdx基础语法(转至指尖流淌)
Mdx为MultiDimensional Expressions的缩写,多维表达式,是标准的OLAP查询语言.在多数OLAPServer都提供Mdx支持,如Microsoft Sql Server ...
- thinkphp 使用外部php或html 原理
- JAVA 并发编程-多个线程之间共享数据(六)
多线程共享数据的方式: 1.假设每一个线程运行的代码同样.能够使用同一个Runnable对象,这个Runnable对象中有那个共享数据,比如,卖票系统就能够这么做. 2,假设每一个线程运行的代码不同. ...
- JavaScript入门之函数返回值
函数返回值 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF ...
- Web前端设计模式--制作漂亮的弹出层
设计场景: Ben最近在负责一个购书网站,在网站的首页上,有一个叫做“最新上架”的板块,板块的内容比较简单,只有书籍名称,作者姓名和上架时间(如图),当初设计的时候并i没有过于丰富的构思... 现在问 ...
- 更改hadoop native库文件后datanode故障
hadoop是用cloudra的官方yum源安装的,服务器是CentOS6.3 64位操作系统,自己写的mapreduce执行的时候hadoop会提示以下错误: WARN util.NativeCod ...
- 【BZOJ3425】Poi2013 Polarization 猜结论+DP
[BZOJ3425]Poi2013 Polarization Description 给定一棵树,可以对每条边定向成一个有向图,这张有向图的可达点对数为树上有路径从u到达v的点对(u,v)个数.求最小 ...
- js 操作对象的引用和操作实际对象的区分
JavaScript高级程序设计-第3版-中 有这么一段话: 在操作对象时,实际上是在操作对象的引用而不是实际的对象.为此,引用类型的值是按引用访问的①. ① 这种说法不严密,当复制保存着对象的某个变 ...