本小结主要总结,Linux下进程的几种状态及其间的相互转换。

 

一、Linux进程的几种状态

1、Linux进程状态:R (TASK_RUNNING),可执行状态

      Linux下处于运行状态和就绪状态的进程,统称为R状态,一个进程只有处于该状态才有可能被CPU执行。同一时刻可以有多个进程处于该状态,处于这些状态的进程都将会被装入一个可执行的队列中,系统中进程调度器的作用就是从这个可执行的队列中选择一个进程进行执行。

 

2、Linux进程状态:S (TASK_INTERRUPTIBLE),可中断的睡眠状态

     Linux中绝大多数的进程都是处于这个状态,处于这个状态的进程是可中断的,比如使用kill发信号让进程退出。一个进程处于该状态往往是由于进程需要等待某些资源进而被挂起,这些资源可能是信号量、socket、io等,所有被挂起的进程也会被放入相应的队列中,当其所要等待的资源到达时,这些进程将会被唤醒。

 

3、Linux进程状态:D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态

     显而易见,处于该状态的进程是不能被中断的,这种型的进程是不接受异步通信产生的信号的,在Linux中这是系统对重要的“事件”的进程提供的一种保护,以避免中断对系统造成不可挽回的操作。

 

4、Linux进程状态:T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态

     在实际应用中,有可能需要给正在运行的进程发送信号,让其处在暂停状态,以便完成调试、跟踪的需求。

 

5、Linux进程状态:Z (TASK_DEAD – EXIT_ZOMBIE),退出状态,进程成为僵尸进程

    父进程创建的子进程后,父子进程将会各自完成自身的任务,子进程在运行完成后将清除本身的资源,并由父进程完成回收,但在子进程还没运行完成,父进程便已处于退出,那么这些还在运行的进程将变成退出状态,即变成僵尸进程,由于系统中还存在一个Init进程(整个Linux的鼻祖进程),系统存在的所有僵尸进程都过继给鼻祖进程,由其来完成回收过程。

 

6、Linux进程状态:X (TASK_DEAD – EXIT_DEAD),退出状态,进程即将被销毁。

      而进程在退出过程中也可能不会保留它的task_struct。比如这个进程是多线程程序中被detach过的进程,或者父进程通过设置SIGCHLD信号的handler为SIG_IGN,显式的忽略了SIGCHLD信号。(这是posix的规定,尽管子进程的退出信号可以被设置为SIGCHLD以外的其他信号。)此时,进程将被置于EXIT_DEAD退出状态,这意味着接下来的代码立即就会将该进程彻底释放。所以EXIT_DEAD状态是非常短暂的,几乎不可能通过ps命令捕捉到。

    在Linux系统中,使用ps aux 命令,我们很容易查看到系统进程的状态,如:

[hello@hello ~]$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1   2900  1440 ?        Ss   22:28   0:01 /sbin/init
root         2  0.0  0.0      0     0 ?        S    22:28   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    22:28   0:00 [migration/0]
root         4  0.0  0.0      0     0 ?        S    22:28   0:00 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S    22:28   0:00 [migration/0]
root         6  0.0  0.0      0     0 ?        S    22:28   0:00 [watchdog/0]
root         7  0.0  0.0      0     0 ?        S    22:28   0:00 [events/0]
root         8  0.0  0.0      0     0 ?        S    22:28   0:00 [cgroup]
root         9  0.0  0.0      0     0 ?        S    22:28   0:00 [khelper]
root        10  0.0  0.0      0     0 ?        S    22:28   0:00 [netns]
root        11  0.0  0.0      0     0 ?        S    22:28   0:00 [async/mgr]
root        12  0.0  0.0      0     0 ?        S    22:28   0:00 [pm]
root        13  0.0  0.0      0     0 ?        S    22:28   0:00 [sync_supers]

     其中的User表示运行系统的用户标识,Pid是当前进程的进程号,%Cpu表示该进程所占用的Cpu资源,%Mem表示该进程所使用的内存资源,VSZ表示进程的虚拟大小,RSS进程驻留集的大小,可以理解为内存中页的数量,TTY表示控制终端的ID,STRAT–这个很简单,就是该进程启动的时间,TIME–进程已经消耗的CPU时间,注意是消耗CPU的时间;COMMOND–命令的名称和参数;STAT–也就是当前进程的状态,其中S-睡眠,s-表示该进程是会话的先导进程,N-表示进程拥有比普通优先级更低的优先级,R-正在运行,D-短期等待,Z-僵死进程,T-被跟踪或者被停止等等。

 

二、Linux进程状态间的相互转换

      进程自创建以后,状态可能发生一系列的变化,直到进程退出。而尽管进程状态有好几种,但是进程状态的变迁却只有两个方向——从TASK_RUNNING状态变为非TASK_RUNNING状态、或者从非TASK_RUNNING状态变为TASK_RUNNING状态。也就是说,如果给一个TASK_INTERRUPTIBLE状态的进程发送SIGKILL信号,这个进程将先被唤醒(进入TASK_RUNNING状态),然后再响应SIGKILL信号而退出(变为TASK_DEAD状态)。并不会从TASK_INTERRUPTIBLE状态直接退出。进程从非TASK_RUNNING状态变为TASK_RUNNING状态,是由别的进程(也可能是中断处理程序)执行唤醒操作来实现的。执行唤醒的进程设置被唤醒进程的状态为TASK_RUNNING,然后将其task_struct结构加入到某个CPU的可执行队列中。于是被唤醒的进程将有机会被调度执行。而进程从TASK_RUNNING状态变为TASK_RUNNING状态,则有两种途径:
    1、响应信号而进入TASK_STOPED状态、或TASK_DEAD状态;
    2、执行系统调用主动进入TASK_INTERRUPTIBLE状态(如nanosleep系统调用)、或TASK_DEAD状态(如exit系统调用);或由于执行系统调用需要的资源得不到满足,而进入TASK_INTERRUPTIBLE状态或TASK_UNINTERRUPTIBLE状态(如select系统调用)。