(二)进程管理之进程状态及组织方式

操作系统:linux
处理器:arm
内核版本:4.x

目录:


进程状态

执行ps aux命令可以看到进程有以下这些状态:

Ss、S、I<、I、SN、Ssl、S<、S<s、Rsl、Ssl+、SNsl、S<l、R+等

他们的含义可以通过man ps找到:

PROCESS STATE CODES
       Here are the different values that the s, stat and state output specifiers
        (header "STAT" or "S") will display to describe the state of a process:

               D    uninterruptible sleep (usually IO)
               R    running or runnable (on run queue)
               S    interruptible sleep (waiting for an event to complete)
               T    stopped by job control signal
               t    stopped by debugger during the tracing
               W    paging (not valid since the 2.6.xx kernel)
               X    dead (should never be seen)
               Z    defunct ("zombie") process, terminated but not reaped by its parent

       For BSD formats and when the stat keyword is used, additional characters may 
       be displayed:

               <    high-priority (not nice to other users)
               N    low-priority (nice to other users)
               L    has pages locked into memory (for real-time and custom IO)
               s    is a session leader
               l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
               +    is in the foreground process group

主要关注以下几个状态:

R (TASK_RUNNING)

只有在该状态的进程才可能在CPU上运行。而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应 CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中)。进程调度器的任务就是从各个CPU的可执行队列中分别选择一个进程在该CPU 上运行。(这个状态并不代表正在执行。)

S (TASK_INTERRUPTIBLE)

处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。这些进程的task_struct结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发、或由其他进程触发),对应的等待队列中的一个或多个进程将被唤醒。

D (TASK_UNINTERRUPTIBLE)

与TASK_INTERRUPTIBLE状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。

Z(EXIT_ZOMBIE)

僵尸状态,此时进程相关资源已经被释放,但还保留着task_struct结构体。当父进程执行wait4调用获取其相关信息时,进程将变为DEAD状态人间蒸发。由于这个过程很短暂,所以很难捕捉到。

这里写图片描述
如上图所示,内核中大部分进程生命周期就在这些状态中转换。通过fork或者clone系统调用,产生新的进程。处于运行状态的进程由于需要等待资源,进入睡眠态,根据能不能被信号唤醒分为TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE两种,资源来临时进程会被wake_up变成TASK_RUNNING,进入rq队列等待调度器调度。进程执行任务完毕后主动退出或被信号杀死时,进入僵尸态等待父进程回收。


其他进程状态

除了上面介绍的那些进程状态外,task_struct的state还可以取其他的值。

/* Used in tsk->state: */
#define TASK_RUNNING                    0x0000
#define TASK_INTERRUPTIBLE              0x0001
#define TASK_UNINTERRUPTIBLE            0x0002
#define __TASK_STOPPED                  0x0004
#define __TASK_TRACED                   0x0008
/* Used in tsk->exit_state: */
#define EXIT_DEAD                       0x0010
#define EXIT_ZOMBIE                     0x0020
#define EXIT_TRACE                      (EXIT_ZOMBIE | EXIT_DEAD)
/* Used in tsk->state again: */
#define TASK_PARKED                     0x0040
#define TASK_DEAD                       0x0080
#define TASK_WAKEKILL                   0x0100
#define TASK_WAKING                     0x0200
#define TASK_NOLOAD                     0x0400
#define TASK_NEW                        0x0800
#define TASK_STATE_MAX                  0x1000

/* Convenience macros for the sake of set_current_state: */
#define TASK_KILLABLE                   (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
#define TASK_STOPPED                    (TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED                     (TASK_WAKEKILL | __TASK_TRACED)

TASK_WAKEKILL:收到致命信号时,唤醒进程。调用vfork时,父进程就会处与
TASK_KILLABLE状态(TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)。

TASK_PARKED、TASK_WAKEKILL、TASK_NOLOAD、TASK_NEW都是内核为了实现一些特殊功能,而存在的特殊state,这里挖一个小坑不展开。


组织方式

这里写图片描述
除了这种树以外,内核还采用链表、hash table和radix tree来组织进程PCB。基树是一种节省空间的数据结构,利用它可以从pid找到task_struct的地址。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_33160790/article/details/80738958