进程的挂起、阻塞和睡眠
https://www.cnblogs.com/ck1020/p/6669661.html
要说挂起、阻塞、睡眠难免让人想到进程生命周期中的阻塞态或者等待状态,而挂起和睡眠却没有出现在进程生命周期中,说明这三个其实在本质上区别并不那么大,但是既然称呼不同,应该就有不同的道理。
先说阻塞,既然它能出现在进程生命周期,必然是每个进程都会经历的一个阶段,众所周知,进程在运行过程中必然要获取资源,暂且不说CPU,进程运行肯定要和磁盘进行交互,继而发生IO操作,IO操作势必要引起等待,在资源未读取完成,进程必然要等待,那么在等待IO完成这个部分就是阻塞状态。所以从这里来看,阻塞是一种被动的方式,由于获取资源获取不到而引起的等待。
再说睡眠,睡眠就是一种主动的方式,其实个人认为睡眠和阻塞在一个层次上,为何这么说呢?当一个进程获取资源比如获取最普通的锁而失败后,可以有两种处理方式,1、自己睡眠,触发调度;2、忙等待,使用完自己的时间。所以从这里看,睡眠的确是一种主动的方式,且仅仅作为一种处理手段。当然睡眠不仅仅用于阻塞,更多的,我们可以在适当的时候设置让进程睡眠一定的时间,那么在这里,就可以发现,睡眠之前,我们已经预先规定了,你只能睡多长时间,这段时间过后,比必须返回来工作。
最后说挂起,挂起也是一种主动的行为,具体而言,挂起是系统层面对进程作出的合理操作。本来想说调度,但是进程调度作为专业术语指CPU资源的分配,那么这里就说操作。挂起的标志就是换出到外存,在外存的进程肯定是不能执行的,所以挂起的目的就很明显,在内存资源不足时,需要把一些进程换出到外存,给着急运行的进程腾地方。挂起倾向于换出阻塞态的进程,也可以是就绪态的进程。只是这个转换几乎不会采用,因为任意时刻,肯定可以找到在内存中的阻塞态进程,但也不能缺少这种直接把就绪转换到挂起的能力。
其实相比之下,睡眠和其他两个结合的不太紧密,有资料说挂起释放内存,而阻塞不释放内存也有一定的道理。下面结合一个图看挂起和阻塞的状态转换:
- 就绪态:进程在内存中并可以执行。
- 阻塞态:进程在内存中并等待一个事件。
- 阻塞/挂起态:进程在外存中并等待一个事件。
- 就绪/挂起态:进程在外存中,但是只要被载入内存就可以执行。
阻塞和挂起之间的相互转换如下:
阻塞→阻塞/挂起:如果没有就绪进程,则至少一个阻塞进程被换出,为另一个没有阻塞的进程让出空间。如果操作系统确定当前正在运行的进程,或就绪进程为了维护基本的性能要求而需要更多的内存空间,那么,即使有可用的就绪态进程也可能出现这种转换。
阻塞/挂起→就绪/挂起:如果等待的事件发生了,则处于阻塞/挂起状态的进程可以转换到就绪/挂起状态。注意,这要求操作系统必须能够得到挂起进程的状态信息。
就绪/挂起→就绪:如果内存中没有就绪态进程,操作系统需要调入一个进程继续执行。此外,当处于就绪/挂起态的进程比处于就绪态的任何进程的优先级都要高时,也可以进行这种转换。这种情况的产生是由于操作系统设计者规定调入高优先级的进程比减少交换量更重要。
就绪→就绪/挂起:通常,操作系统更倾向于挂起阻塞态进程而不是就绪态进程,因为就绪态进程可以立即执行,而阻塞态进程占用了内存空间但不能执行。但如果释放内存以得到足够空间的唯一方法是挂起一个就绪态进程,那么这种转换也是必需的。并且,如果操作系统确信高优先级的阻塞态进程很快将会就绪,那么它可能选择挂起一个低优先级的就绪态进程,而不是一个高优先级的阻塞态进程。
参考:《操作系统:精髓与设计原理(原书第6版)》