进程间的通信
前面在聊到进程的概念的时候,我们知道,进程在操作系统中是一个个相互独立的个体,也就是说,在没有外力介入的条件下,进程之间相互独立,是无法相互看见对方的。
那么操作系统是如何使进程之间相互独立,无法看见对方呢?这里用到了一种叫做虚拟内存的技术。
在前面聊到动态库的时候,我们提过一句虚拟内存的机制。(想要看动态库内容的朋友点这里)
那么究竟虚拟内存是个什么情况呢?
这个就是虚拟内存到物理内存转化的示意图,也就是说,我们用高级语言写出来的程序,其中指针所指向的地址,其实是虚拟地址。
进程1和进程2在创建出来的时候,都会认为它本身独占4G内存。但实际上,这4G内存是操作系统提供的虚拟地址,只有通过页表转化成物理地址的部分,才占有实际的物理内存。
那么为什么要 使用虚拟地址呢?
其实在早期的时候,加载程序是使用物理地址的,但是后来发现各个相互独立的进程之间可能会发生影响,如果一个进程访问出错,越界访问到了别的进程,那么这两个进程最终可能都会挂掉。
所以后来智慧的程序猿就研究出了这样的方法,也就是虚拟内存机制,这极大的提升了进程的独立性,但是也带来了一些问题。
比如,两个进程的确有一些需求,想要进行一些数据传输。
多个进程之间共享同样的资源。
一个进程需要向另一个进程发送消息,通知它们发生了某种事件。
有些进程希望完全控制另一个进程,此时控制进程希望能够拦截另一个进程所陷入的异常,并且能够及时知道它的状态改变(Debug进程)。
这就是我们进程通信的目的。
而现在我们需要通过一些手段来进行进程间的通信,既然进程之间是相互独立的,它们之间相互无法看见,那么作为进程的管理者,当然是有办法看见不同的进程了。
所以我们现在进程通信的方法,都是两个进程通过某种中间的媒介,来达到通信的目的。
现在常见的进程通信有以下分类:
-
管道:
匿名管道pipe。
命名管道。 -
System V IPC
消息队列
共享内存
信号量 -
POSIX IPC
消息队列
共享内存
信号量
读写锁
但是一旦涉及到通信,势必会涉及到同步和互斥的问题!
首先解释什么叫做同步:同步就是进程间的相互制约,多个进程需要相互配合完成一项任务。
举个栗子:A进程是一个打印进程,B进程是一个计算进程,A进程要打印B进程的执行结果,在执行过程中,A进程先运行了,但是等A执行到打印那一步的时候,B进程的结果还没有计算出来,这个时候A进程就被阻塞在这里了,只有等B执行出计算结果的时候,A进场才可以完成打印。在A进程阻塞等待B进程的过程就可以理解为同步。
那么什么是互斥呢?
互斥是由于多个进程之间需要访问临界资源,而临界资源同时只能被有限个进程访问,各个进程需要相互竞争使用这些资源,这种关系称为互斥。
临界资源:同时只允许有限个进程访问的资源,被称之为临界资源,访问临界资源的代码叫做临界区。
同样,举个栗子:A进程和B进程都是打印进程,但是这台计算机只有一台打印机,A和B同时只能有一个进程在访问打印机,那么A和B就是互斥关系,打印机就是临界资源。
进程之间的通信在很多情况下都会涉及到同步互斥,比如两个进程,一端在读,一端在写,那么写端在写的时候,读端就不能读,否则可能会读出错误信息。而读端在读的时候,写端就不能写,否则还是可能会造成信息不对称。