进程间的几种通信方式
进程间主要的通信方式为:信号、管道(通常分为无名管道、命名管道)、消息队列、共享内存。
一、管道
管道通常分为无名管道PIPE和有名管道FIFO。除了建立、打开、删除的方式不同外,这两种管道几乎是一样的。他们都是通过内核缓冲区实现数据传输。
特点:
1)管道是半双工的,数据只能向一个方向流动,需要双方通信时,需要建立起两个管道;
2) 无名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
3) 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
无名管道(PIPE):
pipe用于相关进程之间的通信,例如父进程和子进程,它通过pipe()系统调用来创建并打开,当最后一个使用它的进程关闭对他的引用时,pipe将自动撤销。
进程只能访问自己或祖先创建的管道,而不能访任意访问已经存在的管道——因为没有名字。
父进程创建管道,并在管道中写入数据,而子进程从管道读出数据
有名管道(FIFO):
命名管道有一个名字,命名管道的名字对应于一个磁盘索引节点,有了这个文件名,任何进程有相应的权限都可以对它进行访问。
一旦建立,任何进程都可以通过文件名将其打开和进行读写,而不局限于父子进程,当然前提是进程对FIFO有适当的访问权。当不再被进程使用时,FIFO在内存中释放,但磁盘节点仍然存在。
二、信号
信号用于通知接收进程某个事件已经发生。
信号可以在任何时候发送给某一进程,而无须知道该进程的状态。如果该进程并未处于执行状态,则该信号就由内核保存起来,知道该进程恢复执行并传递给他为止;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。
信号可以在用户空间进程和内核之间直接交互。内核也可以利用信号来通知用户空间的进程来通知用户空间发生了哪些系统事件。信号事件有两个来源:
1)硬件来源,例如按下了cltr+C,通常产生中断信号sigint
2)软件来源,例如使用系统调用或者命令发出信号。
一旦有信号产生,用户进程对信号产生的相应有三种方式:
1)执行默认操作 2)捕捉信号 3)忽略信号
1、信号发送:
信号发送的关键使得系统知道向哪个进程发送信号以及发送什么信号2、信号处理
当某个信号被发送到一个正在运行的进程时,该进程即对次特定的信号注册相应的信号处理函数,以完成所需处理。3.信号阻塞
有时候既不希望进程在接收到信号时立刻中断进程的执行,也不希望此信号完全被忽略掉,而是希望延迟一段时间再去调用信号处理函数
三、消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
用户进程可以向消息队列添加消息,也可以向消息队列读取消息。消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
四、共享内存
共享内存,指两个或多个进程共享一个给定的存储区。
共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取读出,从而实现了进程间的通信。
特点
1.共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
2.因为多个进程可以同时操作,所以需要进行同步。
3.信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
共享内存有两种实现方式:1、内存映射 2、共享内存机制
1、内存映射
内存映射 memory map机制使进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read/write等文件操作函数。
2、共享内存机制
IPC的共享内存指的是把所有的共享数据放在共享内存区域,任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。
总结
1.管道:速度慢,容量有限,只有父子进程能通讯
2.FIFO:任何进程间都能通讯,但速度慢
3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题
4.信号量:不能传递复杂消息,只能用来同步
5.共享内存区:能够很容易控制容量,速度快,但要保持同步,相当于线程中的线程安全。