用户空间和内核空间
操作系统可以支持多个进程应用同时运行,这就需要保证不同进程间不相互干扰,即一个进程崩溃不会影响其他进程、也不能去扰乱其他进程运行。这就需要操作系统对用户进程进行调度管理,于是内存空间被划分为用户空间和内核空间,用户空间进行数据处理,而对数据读写以及进程调度则由权限更高的内核空间处理。
进程上下文切换
- 一个程序在执行的过程中,当中断(interrupt) 或 系统调用(system call) 发生时,会使得当前进程失去对 CPU 的控制权,由操作系统内核接管 CPU 的控制权。
- 操作系统内核负责保存进程 P0P_0P0 在 CPU 中的上下文(程序计数器, 寄存器)到 PCB0PCB_0PCB0 ——操作系统分配给进程的一个内存块中。
- 从PCB1PCB_1PCB1取出进程 P1P_1P1 的CPU上下文, 将CPU控制权转移给进程 P1P_1P1 , 开始执行进程 P1P_1P1 的指令。
- 当进程 P1P_1P1 执行完成后,同样由操作系统内核接管 CPU 的控制权,并保存进程 P0P_0P0 在 CPU 中的上下文到 PCB1PCB_1PCB1 。
- 从PCB0PCB_0PCB0取出进程 P0P_0P0 的CPU上下文, 将CPU控制权转移给进程 P0P_0P0 , 继续执行进程 P0P_0P0 的指令。
进程通信
简单地说,进程之间需要进行通信时,进程A会将数据从用户空间的缓冲区拷贝到内核空间的缓冲区,进程B再从内核空间的缓冲区将数据读走。
进程间通信需要借助操作系统提供的特殊的方法,文件、管道、信号、共享内存、消息队列、套接字、命名管道等,这里不作展开。
Blocking/Nonblocking、Synchronous/Asynchronous
阻塞( Blocking ) /非阻塞( Nonblocking) 同步(Synchronous)/异步( Asynchronous)的区别可以参考《操作系统概念》中关于进程间通讯这一部分内容。
进程间的通信时通过 send() 和 receive() 两种基本操作完成的。具体如何实现这两种基础操作,存在着不同的设计。 消息的传递有可能是阻塞的或非阻塞的 —— 也被称为同步或异步的:
- 阻塞式发送(blocking send). 发送方进程会被一直阻塞, 直到消息被接受方进程收到。
- 非阻塞式发送(nonblocking send)。发送方进程调用 send() 后, 立即就可以其他操作。
- 阻塞式接收(blocking receive) 接收方调用 receive() 后一直阻塞, 直到消息到达可用。
- 非阻塞式接受(nonblocking receive) 接收方调用 receive() 函数后, 要么得到一个有效的结果, 要么得到一个空值, 即不会被阻塞。
上述不同类型的发送方式和不同类型的接收方式,可以自由组合。
从进程通讯上来看,阻塞或非阻塞 以及 同步或异步是近义词。
- 同步:即阻塞发送,发送方A调用 send() 方法与接收方B通信,由于是同步的,那么在发送方A进程所对应的系统内核空间中,内核缓冲区的数据没发送出去之前,发送方A进程都是一直等待的
- 异步:即非阻塞发送,发送方A调用 send() 方法与接收方B通信,由于是异步,发送方A进程只需要把要发送的消息由用户空间拷贝到内核空间,不用等到内核缓冲区的消息发送出去,就可以处理其他逻辑
- 阻塞:针对的是接收方,如果发送方A给接收方B要发送消息,接收方B调用receive()方法,如果内核缓冲区中没有数据或者没有到达指定大小的数据,那么接收方B进程就会一直阻塞,直到符合满足返回数据的条件
- 非阻塞:针对的是接受方,如果发送方A给接收方B要发送消息,接收方B调用receive()方法,如果内核缓存区中没有数据,那么接收方B就会返回一个空值,不会阻塞
进程阻塞
进程阻塞是指进程在发起了一个系统调用(I/O or event wait)后,由于该系统调用的操作不能立即完成,需要等待一段时间,于是内核将进程挂起为等待状态,以确保它不会被调度执行,占用 CPU 资源。
这里阻塞或非阻塞描述的是进程是否变为等待状态,变为等待状态则说明发生了阻塞。
一般来说,应用级程序都被设置为阻塞式的系统调用,阻塞式代表着代码执行顺序和编写顺序是一致的,从而使得应用级代码编写十分容易。