进程(2)——进程状态(僵尸,睡眠……)【linux】
- 一.操作系统的进程状态:
- 1.1 运行态
- 1.2 阻塞态
- 1.3 挂起态
- 二.linux进程状态
- 2.1 R——运行状态
- 2.2 S——浅度睡眠状态
- 2.3 D——(disk sleep)深度睡眠
- 2.4 t/T(stop)
- 2.5 X:(dead)
- 2.5 Z:(zombie)
- 三.孤儿进程:
一.操作系统的进程状态:
我们知道进程有多个
假设现在只有一个一个CPU,那进程会去争抢cpu的资源。
这个时候cpu会有一个运行队列,来实现让进程按照顺序执行。
这个是进程的运行队列,一个个进程都加载进运行队列中。
这个时候对应进程的代码和数据都加载进了进程之中
所以说内存不光要维护PCB,同时还管理着程序的代码和数据。
1.1 运行态
在运行队列中的进程就是运行态
1.2 阻塞态
因为进程未被内存读取前是在磁盘中的程序,所以对进程的管理实际上是操作系统对软件的管理
如果进程需要访问硬件(设备)中的资源,这个时候就要涉及到操作系统对进程的管理。
操作系统管理硬件也是先描述再组织,对硬件也会进行描述,硬件中有等待队列。
每个设备都有个等待队列
比如说一个进程需要键盘进行输入,操作系统就会让该进程进入到该设备等待队列。
在设备的等待队列中的进程就叫阻塞态
比如说C语言的scanf函数等待输入时,这个时候就是阻塞状态
1.3 挂起态
我们要注意,当进程处于阻塞态中
进程的自身代码和数据还是存在内存中。
如果这时候进程在阻塞态中等待设备资源就位时
突然操作系统内部的内存资源不足了。
操作系统就会在进程中进行检查
将一些在挂起态的进程的pcb保留,将内存中的代码和数据从内存中丢弃
当进程所需的设备资源就位时,再将数据和代码从磁盘中重新读取
二.linux进程状态
上面的操作系统中的进程状态我们只是随便提一下而已。
我们的学习重心还是要放在Linux系统的进程状态上来。
2.1 R——运行状态
这里我们那test.c进程测试一下
这里用grep进行测试。
这里我们能发现test处于R+的运行状态。
这里的+先不谈,之后的博客中会进行讲解。
2.2 S——浅度睡眠状态
这里的S的睡眠状态,可以看成是操作系统中的阻塞状态。
这这里我们同样可以进行测试一下:
这里我们能发现进程一直处于设备资源的到位,处于S的阻塞状态。
2.3 D——(disk sleep)深度睡眠
前面我们在操作系统进程的挂起态中我们提到:
当内存太满的时候,系统有可能,会自己干掉进程
但是如果遇到一个进程正在向磁盘写入数据,正好被干掉的话,就会导致数据的丢失。
如果正好是比较重要的数据,那这个后果是不能承受的
所以创建了一个深度睡眠模式
专门交给那些向磁盘写入数据的进程。
防止系统误杀进程,从而造成数据丢失。
2.4 t/T(stop)
这个状态可以看作是程序处于设备等待队列的阻塞状态。
只不过这个阻塞状态不光是系统控制的,我们用户可以进行停止和继续。
这里就比如说gbd调试
我们打了断点后进程运行到断点处,就会进入stop状态
这里我们在程序的第四行打一个断点,然后运行程序。
就会发现这里的进程处于:
gdb test会等待指令进行下一步的阻塞态
而test处于t状态
2.5 X:(dead)
终止状态 :在相关进程丢尽垃圾队列中等待释放。
2.5 Z:(zombie)
当子进程死了以后,不会立马进行释放,而是会保留子进程的PCB以及内存和资源,让关心子进程的进程或者父进程来检查。
确定了子进程的结束原因以后,之后再在放入终止状态。
这个保留PCB和内存资源的状态,就叫僵尸状态
这里可以来测试一下
这里我们用fork函数,让子进程消失,让父进程保留。
这里我们会发现这里的子进程处于Z状态
所以如果僵尸进程处理不当就会引起内存泄漏:
进程一般退出的时候,如果父进程没有主动回收子进程的信息。
子进程会一直让自己处于Z状态,进程相关资源尤其是task_struct不会被释放。
僵尸进程会一直占用内存资源(内存泄漏)。
就比如我们上面的测试代码,这个时候子程序会一直处于僵尸状态。
至于如何处理,这个就留到之后的博客了
三.孤儿进程:
父子进程,父进程先退出,子进程的父进程会被改成1号进程(操作系统),相当于被系统给领养
这里可以来测试一下:
这里我们让父进程先走,然后不停打印子进程的父进程pid
这里我们就能发现父进程从3090变成了1
这里就看出子进程被操作系统给收养了。
为什么要领养:
因为子系统进入Z状态的话,这样就没有人来收尸了。