目录
1.什么是进程通信?
进程通信( InterProcess Communication,IPC)就是进程之间进行信息交换;可能有以下情形:
- 进程之间数据传输
- 进程之间资源共享
- 进程之间消息通知
2.进程通信原理
每个进程都有独立的用户地址空间,进程A不能直接访问进程B的地址空间。因为内核空间是每个进程共享的,因此,进程之间通信,就可以在内核开辟一块缓冲区,进程通过内核缓冲区进行信息交换。
3.进程通信机制
进程通信机制常见有以下几种:
- 管道(匿名管道和有名管道,也被称为文件共享机制)
- 消息队列
- 共享内存和信号量
- 信号
- socket(不同系统间也可以用)
3.1 管道
3.1.1匿名管道
类似这样的命令:
ps -aux|grep ssh
其中竖线 | 把两个命令连接起来,这个竖线叫管道符,意思是将前一个命令 ps -aux的输出结果当做后一个命令 grep ssh的输入。管道命令是单向的,如果要实现双向通信,需要两个管道。
上面这种 | 管道属于匿名管道,匿名管道用完自动销毁,且匿名管道只能在父子进程之间通信。
在linux编码中,使用PIPE函数创建匿名管道。
创建匿名管道实现通信的步骤如下:
- 父进程创建管道1,父进程pipe fd[0]指向管道读端,父进程fd[1]指向管道写端;
- 父进程fork子进程,子进程同样指向管道的读写两端;
- 父进程关闭管道读端,子进程关闭管道写端;这样就形成父进程写入,子进程读出的单向通信,如果想实现父子双向通信,则需要再创建一个管道,实现子进程写父进程读的通信。
从上面可以看出,匿名管道就是在内核中开辟一个缓冲区,这个缓冲区关联管道文件,对管道文件的操作其实就是对内核缓冲区的操作。
3.1.2 有名管道(FIFO)
匿名管道只能用于父子进程通信;有名管道提供一个路径名与其关联,即使进程间不存在亲缘关系的进程,只要访问该路径,就能够通过Fifo进行通信;
linux使用mkfifo创建有名管道,FIFO的意思是先进先出机制。
有名管道实现进程通信的步骤:
- mkfifo创建管道文件,如mkfifo testpipe
- 然后进程A可以往testpipe文件写入内容
- 进程B从testpipe中读出内容
3.2 消息队列
消息队列本质上是一个链表,进程A与进程B要通信,A把数据扔到队列,B到队列读取数据,反过来一样,这样就实现了AB之间的通信。消息队列本质是一个链表,因此它支持多个进程读写信息,同时支持随机查询,且读写进程可以实现异步操作。
消息队列有一个值得注意的问题是:用户写输入到消息队列时,是将用户态数据写入内核态;同样,读取消息队列的数据时,是将内核态数据读到用户态。因此读写消息队列数据,会造成系统调用,如果频繁读写数据,就会频繁系统调用。
消息队列生命周期随内核,关闭操作系统或释放消息队列,消息队列才会销毁。
3.3 共享内存 和 信号量
3.3.1 共享内存
共享内存是指不同的进程将自己的地址空间连接到同一块物理内存,这些进程可以访问同一块物理内存。某进程向这块共享物理内存写入数据,其他所有连接到该共享物理内存的进程都可以访问该数据。
不同于消息队列频繁的系统调用,对于共享内存机制来说,仅在建立共享内存区域时需要系统调用,一旦建立共享内存,所有的访问都可作为常规内存访问,无需借助内核。这样,数据就不需要在进程之间来回拷贝。
3.3.2 信号量
共享内存通信机制可能会发生冲突,比如同时有多个进程来修改共享内存,先来的修改会丢失或者出现脏数据。
进程之间是存在同步、互斥两种场景的。同步就是进程之间合作,按照顺序依次执行,互斥就是对某一共享资源任何时候保证只有一个进程可访问。
信号量与PV操作就是解决进程同步与互斥的一种方案,具体关于信号量、PV操作可查询操作系统相关内容(后续应该也会刷这块儿)。
总之,进程之间通过传输信号量,实现进程的同步与互斥,保护进程通信。
3.4 信号
信号跟信号量完全不是一码事儿。
比如kill -9 121就是给PID为121的进程发送kill 信号,让进程立即结束。
信号机制是通过发送信号给某个进程,以通知该进程执行信号程序。
linux下,信号程序有:
3.5 SOCKET套接字
套接字可以实现跨网络的不同主机之间的通信。
关于socket,内容涉及计算机网络,下次再专门写一篇socket的介绍和实践。