操作系统之进程间通信篇
本文主要阐述Linux系统中的进程如何进行通信,因为每个进程的用户地址空间都是独立的,一般不能互相访问,但内核空间是每个进程都共享的,所以Linux中的进程通信必须通过内核。在Linux内核进程间通信主要有以下6种方式:
一、管道
概念:把前一个命令的结果当成后一个命令的输入。
管道实质上是内核管理的一个缓冲区,进程写入的数据都存在内核中,另一个进程读取数据时自然也是从内存中读取,同时通信数据遵循先进先出原则,管道的生命周期随进程的创建而建立,随进程的结束而销毁。管道这种通信方式效率低,不适合进程间频繁的交换数据。
分类:
匿名管道:它存在于内存,不存在于文件系统中且没有名字标识,Linux命令中的 | 就是匿名管道,匿名管道通信的数据是无格式的流且大小受限,通信方式是单向的,匿名管道只能用于存在父子关系的进程间通信。
命名管道:命名管道实现了毫无关系的进程间通信。
二、消息队列
消息队列解决了管道的进程间频繁的交换数据效率低的问题,A进程向B进程发送消息,A进程把数据放在对应的消息队列就可以返回了,B进程需要的时候再去读取数据就可以了。消息队列的实质是保存在内核中的消息链表,在发送数据时,会分成一个一个独立的消息体,消息的发送方和接受方都要约定好消息体的数据类型,所以每个消息体都是固定大小的存储块,不像管道是无格式的字节流数据,进程从消息队列中读取了消息体,内核就会把这个信息删除。在通信过程中,存在用户态与内核态之间的数据拷贝开销。
缺点:
1.通信不及时。
2.不适合较大数据传输。
三、共享内存
消息队列的读取和写入的过程中,都会有用户态与内核态之间的数据拷贝过程,共享内存则解决了这个问题。在Linux操作系统中,对内存的管理采用的虚拟内存技术,如果对内存管理不熟悉的同学,请看操作系统之内存管理篇。在这里我们只需知道每个进程都有自己独立的虚拟空间,不同进程的虚拟空间映射到不同的物理内存中,即使进程的虚拟地址是一样的,其实访问的是不同的物理地址,对于数据的增删查改互不影响。共享内存的机制就是拿出一块虚拟空间出来,映射到相同的物理内存中。这样进程写入的东西,另一个进程马上就能看见,不需要数据的拷贝,提高了进程间的通信速度。
缺点:
多个进程同时修改同一个共享内存,很有可能会引起冲突。
四、信号量
信号量主要用于实现进程间的互斥与同步,这里的互斥与同步与线程相同,主要是P、V操作,不懂的同学可以参考操作系统之多线程资源竞争篇,而不是用于缓存进程间通信的数据。信号量防止多进程共享资源,导致数据的混乱。
五、信号
信号与信号量两者用途完全不一样,上述4种通信方式都是在常规状态下的工作模式,当对于异常情况下的工作模式,就需要用信号的方式来通知进程。信号是进程间通信机制中唯一的异步通信机制,信号事件来源主要有硬件来源(如键盘Ctrl+C)和软件来源(如kill命令)。
一旦有信号产生,进程有3种响应信号:
1.执行默认操作,Linux对每种信号都规定了默认操作。
2.捕捉信号,可以为信号定义一个信号处理函数,当信号发生时,就执行相应的信号处理函数。
3.忽略信号,当我们不希望处理某些信号的时候,就忽略信号。
但是有两个信号是应用进程无法捕捉和忽略的,即SIGINT(kill命令)和SEGSTOP,它们用于在任何时候中断或结束某一进程。
六、Socket
Socket不但可以用于不同主机的进程间通信,还可以用于本地主机进程间通信。
类型:
1.基于TCP协议的通信方式。
2.基于UDP协议的通信方式。
3.本地进程间通信方式。