在现代操作系统当中,我们可以很方便的编写出多进程程序。在多进程程序中,如果多个进程之间需要协作完成任务,那么进程间通信的方式就是需要重点考虑的事项之一。这种通信通常被叫做IPC(Inter-Process Communication),不同版本的Unix及其衍生操作系统所支持的IPC方法都不尽相同,下面讨论的IPC时只针对Linux系统。
Linux操作系统可以使用的IPC方法有多种,从处理机制角度看,他们可以分为三类:
基于通信的IPC方法分为:
基于信号的IPC方法:
基于同步的IPC方法:
进程的定义
进程是所有Unix及其衍生操作系统的根本,因为所有的程序都在进程中被执行。通常我们把一个程序的执行称之为一个进程。反过来讲,进程用来描述程序的执行过程。程序和进程分别描述了一个程序的静态形式和动态特征。除此之外。进程是操作系统进行资源分配的基本单位。
进程的衍生
进程使用fork(一个系统调用函数)可以创建若干个新的进程,其中前者称为后者的父进程,后者称为前者的子进程。每个子进程都是源自它父进程的一个副本,它会获得父进程的数据段、堆、栈的副本,并于父进程共享代码段。每一个副本都是独立的,子进程对于它副本的修改对其父进程和兄弟进程都是不可见的,反之亦然。全盘复制父进程的数据是一种相当低效的做法,Linux操作系统内核使用写时复制COW(Copy on wite)等技术来提高创建进程的效率。
Unix操作系统中每一个进程都有父进程,所有的进程共同组成一个树状结构,内核启动程序作为进程树的根,负责系统的初始化操作。如果一个进程先于它的子进程结束,那么这些子进程将会被内核启动程序“收养”,成为它的直接子进程。
进程的标识
为了管理进程,内核必须对每一个进程的属性和行为进行详细的记录,包括进程的优先级、状态、虚拟地址范围、各种访问权限等。更具体的说这些信息都被记录在进程描述符中,进程描述符并不是一个简单的符号,而是一个非常复杂的数据结构。保存在进程描述符中的进程ID(常称为PID)是进程在操作系统中唯一标识,进程号为1的进程就是内核启动进程。
进程的状态
在Linux操作系统中,每个进程每时每刻都是友状态的,可能的状态共有如下6种:
进程在其生命周期内可能会产生一系列的状态变化。简单的说,进程的状态只会在可运行状态和非可运行状态之间转换,下图展示了一般情况下的进程状态切换。
进程的空间
用户进程(或者说程序的执行实例)总会生存在用户空间中,他们可以做很多事情,但是却不能与其所在计算机硬件进行交互。内核可以与硬件交互,但是它却生存在内核空间中。用户进程无法直接访问内核空间。用户空间和内核空间都是操作系统在内存上划分的一个范围,他们共同瓜分了操作系统能够支配的内存区域。
内存区域中的每一个单元都是有地址的,用指针来标识和定位,通过指针来寻找内存单元的操作也称为内存寻址。指针是一个二进制正整数,位数由操作系统决定(32,64)。这里所说的地址物理内存中的真实地址,而是虚拟地址,而由虚拟地址来标识的内存区域又称为虚拟地址空间,也称虚拟内存。内核会为每一个用户进程分配虚拟内存,进程的虚拟内存几乎是彼此独立、互不干扰的,这是由于它们基本上被映射到了不同的物理内存上。内核会把进程的虚拟内存划分为若干页,而物理内存单元的划分由cpu负责。一个物理内存单元被称为一个页框,不同进程的大多数页都会与不同的页框对应,当然页框共享也是允许的,这是共享内存区(一种IPC方法)的基础。
系统调用
用户进程无法直接访问内核空间,也无法随意指示内核去做它能做的一些事。但是为了使用户进程能够使用操作系统更底层的功能,内核会暴露一些接口以供他们使用,这些接口是用户进程使用内核功能(包括操纵计算机硬件)的唯一手段,也是用户空间和内核空间的一座桥梁。用户使用这些接口的行为称为系统调用。
说到系统调用,就不得不提及另一对概念--内核态和用户态。为了保证操作系统的稳定和安全,内核依据由cpu提供的、可以让进程驻留的特权级别建立了两种状态。当用户进程发送一个系统调用的时候,内核会把cpu从用户态切换到内核态,让cpu执行对应的内核函数,当执行完成后会将cpu状态切换为用户态,并把执行结果返回给用户进程。
进程切换和调度
与其他操作系统一样,Linux操作系统也可以凭借cpu快速的在多个进程间进行切换,这也称为进程间的上下文切换。如此会产生多个进程同时运行的假象,而每个进程都会认为自己独占了cpu,这就是多任务操作系统这个称谓的由来。不过,切换速度如何,在同一时刻正在运行的进程仅会有一个。
进程切换由内核完成。切换cpu正在运行的进程是需要付出代价的。例如,内核此时要换下正在上运行的A进程,运行B进程,在换下A之前要保存A的运行状态,同时将B进程的相关信息恢复到之前B被换下时候的运行状态。为了使各个生存着的进程都有被运行的机会,内核还要考虑下次切换时运行哪个程序、何时进行切换、被换下的进程何时被换上等,解决这类类似问题的方案和任务统称为进程调度。进程切换和进程调度是多个程序并发执行的基础。
内核对进程的切换和调度使得多个进程可以有条不紊地并发运行。在很多时候,多个进程之间需要相互配合共同完成一个任务,这就需要IPC地支持。
后续再更...