转载自:博学谷
一、进程状态
在三态模型中,进程状态分为三个基本状态,即
运行态,就绪态,阻塞态
。
在五态模型中,进程分为
新建态、终止态,运行态,就绪态,阻塞态
。
通过fork()创建进程,然后该进程进入就绪态,通过进程调度(进程优先级越高,调度该进程的可能性越大),进程进入运行态,当该进程的时间片到时,进程重新回到就绪态。该进程在运行态时,若该进程的子进程结束了,但是父进程还在,那么父进程就是个僵尸进程,那么它被终止之后就死亡了,其不再能够复活;该进程在运行态时,若进程执行完毕或者接收到(内核发送的)SIGSTOP和SIGTSTP信号,就进入到停止态,停止态若要被唤醒到就绪态,就要接收到SIGCONT信号。
不可中断等待态和可中断等待态区别:该进程是否可以被暂停。
Q:怎么表示父进程和子进程?
A:除了进程0以外的所有进程都是由其他进程使用系统调用fork创建的,这里调用fork创建新进程的进程即为父进程,而相对应的为其创建出的进程则为子进程,所以子进程是由父进程创建的,一个子进程只有一个父进程,但一个父进程可以有多个子进程。
#include<unistd.h>
pid_t fork(void);
//返回值:子进程中返回0,父进程返回子进程id,出错返回-1
其中:若上面代码为一段可运行的程序,运行该程序的为父进程,然后fork()创建了一个子进程,子进程的返回值为0, 父进程返回子进程id。
①TASK_RUNNING:
进程正在被CPU执行。当一个进程刚被创建时会处于TASK_RUNNABLE,表示己经准备就绪,正等待被调度。
②TASK_INTERRUPTIBLE(可中断):
进程正在睡眠(也就是说它被阻塞)等待某些条件的达成。一旦这些条件达成,内核就会把进程状态设置为运行。处于
此状态的进程也会因为接收到信号而提前被唤醒
,
比如给一个TASK_INTERRUPTIBLE状态的进程发送SIGKILL信号,这个进程将先被唤醒(进入TASK_RUNNABLE状态),然后再响应SIGKILL信号而退出
(变为TASK_ZOMBIE状态),并不会从TASK_INTERRUPTIBLE状态直接退出。
③TASK_UNINTERRUPTIBLE(不可中断):
处于等待中的进程,待资源满足时被唤醒,
但不可以由其它进程通过信号或中断唤醒
。由于不接受外来的任何信号,
因此无法用kill杀掉这些处于该状态的进程
。而
TASK_UNINTERRUPTIBLE状态存在的意义就在于
,
内核的某些处理流程是不能被打断的
。如果响应异步信号,程序的执行流程中就会被插入一段用于处理异步信号的流程,于是原有的流程就被中断了,这可能使某些设备陷入不可控的状态。处于TASK_UNINTERRUPTIBLE状态一般总是非常短暂的,通过ps命令基本上不可能捕捉到。
④TASK_ZOMBIE(僵死):
表示进程已经结束了,
但是其父进程还没有调用wait4或waitpid()来释放进程描述符
。为了父进程能够获知它的消息,子进程的进程描述符仍然被保留着。一旦父进程调用了wait4(),进程描述符就会被释放。
⑤TASK_STOPPED(停止):
进程停止执行。当进程接收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU等信号的时候。此外,
在调试期间接收到任何信号
,都会使进程进入这种状态。
当接收到SIGCONT信号,会重新回到TASK_RUNNABLE
。
二、查看进程状态
linux下命令:列出目前所有的正在内存中的进程
选项 |
含义 |
---|---|
-a | 显示终端上的所有进程,包括其他用户的进程 |
-u | 显示进程的详细状态 |
-x | 显示没有控制终端的进程 |
-j | 列出与作业控制相关的信息 |
ps aux
ps的作用是显示当前运行的进程。
aux中:a显示用户使用的进程;
u
:使用以用户为主的格式输出进程信息;x显示机器的所有进程。
Q:作业控制是什么?
A:Shell分前后台来控制的不是进程而是作业或者进程组。一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成,Shell可以同时运行一个前台作业和任意多个后台作业,这称为作业控制。
进程显示样式:
stat中的参数意义如下:
参数 |
含义 |
---|---|
D | 不可中断 Uninterruptible(usually IO) |
R | 正在运行,或在队列中的进程 |
S(大写) | 处于休眠状态 |
T | 停止或被追踪 |
Z | 僵尸进程 |
W | 进入内存交换(从内核2.6开始无效) |
X | 死掉的进程 |
< | 高优先级 |
N | 低优先级 |
s | 包含子进程 |
+ | 位于前台的进程组 |
三、孤儿进程
父进程运行结束,但是子进程还在运行的子进程就称为孤儿进程。
每当出现一个孤儿进程,内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。当孤儿进程结束声明周期时,init进程就会处理它的善后工作。所以孤儿进程没有什么危害。
四、僵尸进程
进程终止了,但是父进程还没回收子进程的资源,所以子进程的信息还保留在PCB中,所以还存在内核中,这样子进程就是僵尸进程。
这样就会导致一个问题,如果进程不调用wait() 或 waitpid() 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免。
Q:那遇到僵尸进程怎么处理呢?
A:
init进程回收法:
如果父进程先于子进程结束,那么子进程的父进程自动改为 init 进程。如果 init 的子进程结束,则 init 进程会自动回收其子进程的资源而不是让它变成僵尸进程。