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 " ...
随机推荐
- 纯CSS炫酷3D旋转立方体进度条特效
在网站制作中,提高用户体验度是一项非常重要的任务.一个创意设计不但能吸引用户的眼球,还能大大的提高用户的体验.在这篇文章中,我们将大胆的将前面所学的3D立方体和进度条结合起来,制作一款纯CSS3的3D ...
- Can't zip RDDs with unequal numbers of partitions
java.lang.IllegalArgumentException: Can't zip RDDs with unequal numbers of partitions //如果两个RDD分区数不同 ...
- QTableWidget与QTableView的区别
QTableWidget继承自QTableView.QSqlTableModel能与QTableView绑定,但不能于QTableWidget绑定 QSqlTableModel *model = ne ...
- 清除Css中select的下拉箭头样式
select {/*Chrome和Firefox里面的边框是不一样的,所以复写了一下*/border: solid 1px #000; /*很关键:将默认的select选择框样式清除*/appeara ...
- LigerUI 树状列表折叠显示
http://blog.csdn.net/haojuntu/article/details/8626040 —————————————————————————————————————————————— ...
- mac环境搭建selenium
前言 搭建python+selenium,mac自带python2.7,需要公司使用的python是3.x,可以自己百度安装python环境. 1. selenium安装 1. selenium的安装 ...
- 002杰信-陌生的maven-web项目整改成我们熟悉的Web架构;classpath的含义;ssm框架的整合;junit测试
这篇博客的资源来源于创智播客,先在此申明.这篇博客的出发点是jk项目,传智的做法是Maven的web模板生成的,但是这样子的结构目录与我们熟知的Web项目的结构目录相差很大,所以要按照我们熟知的项目结 ...
- JavaBeans 官方文档学习
提示,重点:JavaBeans的Property和 Events:PropertyEditor极其注册和查找机制. 从目前来看,JavaBeans 更像是源自GUI的需求. 使用NetBeans新建一 ...
- 【剑指offer】翻转单词顺序
转载请注明出处:http://blog.csdn.net/ns_code/article/details/27372033 题目描写叙述: JOBDU近期来了一个新员工Fish,每天早晨总是会拿着一本 ...
- RabbitMQ组成及原理介绍-3
rabbitmq作为成熟的企业消息中间件,实现了应用程序间接口调用的解耦,提高系统的吞吐量. 1.RabbitMQ组成 是由 LShift 提供的一个 Advanced Message Queuing ...