https://github.com/HexTeto/bucket/blob/master/process-state.markdown

Linux 进程状态

Process

Process state

Process control block, PCB



R

R : TASK_RUNNING 为可执行状态, 只有处于该状态的进程才能在 CPU 上运行. 同一时刻可以有多个进程处于可执行状态, 它们的task_struct 进程控制块 (PCB) 被放入对应的 CPU 的可执行队列中 (一个进程最多只能出现在一个 CPU 的可执行队列中).

此外, 有些系统中会将 TASK_RUNNING 状态拆分为:

  • RUNNING : 正在 CPU 上执行的进程
  • READY : 可执行但尚未被调度执行的进程



S

S : TASK_INTERRUPTIBLE 表示可中断的睡眠状态. 处于这个状态的进程因为等待事件而被挂起, 这些进程的 PCB 被放入对应事件的等待队列中, 一旦事件发生, 对应的等待队列中的一个或多个进程将被唤醒.

通过 ps 命令可以看到, 通常绝大多数的进程都是处于 S 状态的 (除非处于高负载状态下).



D

D : TASK_UNINTERRUPTIBLE 表示不可中断的睡眠状态. 该状态与 S 状态的区别就在于不可中断, 这里不可中断指的并不是 CPU 不响应外部硬件的中断, 而是指进程不响应异步信号.

绝大多数情况下, 进程在处于睡眠状态时也是能够响应异步信号的. 否则诸如 kill 等命令就不能杀死一个正在睡眠的进程了.

通常如果一个进程处于 D 状态时, 它表示某些处理流程是不能被打断的. 如果响应异步信号, 程序的执行流程中就会被插入一段用于处理异步信号的流程, 于是原有的流程就被中断了.



T

T : TASK_STOPPED / TASK_TRACED 表示进程处于停止或跟踪状态. 进程接收到一个 SIGSTOP 信号就会进入 TASK_STOPPED 状态 (除非该进程正处于 D 状态), 而随着接收到 SIGCONT 信号恢复到 R 状态.

SIGSTOP 与 SIGKILL 一样是非常强制的, 不允许用户进程通过 signal 系列的系统调用重新设置对应的信号处理函数.

当进程处于 TASK_TRACED 状态时, 则指的是比如 gdb 插入的断点, 此时进程被暂停并等待跟踪它的进程对它进行操作.

TASK_STOPPED 与 TASK_TRACED 的区别在于被跟踪的进程不会响应 SIGCONT 信号, 必须要等待跟踪它的进程通过 ptrace 系统调用执行 PTRACE_CONTPTRACE_DETACH 等操作或者跟踪进程退出, 被跟踪的进程才会恢复 R 状态.



Z

Z : TASK_DEAD - EXIT_ZOMBIE 表示僵尸进程. 所谓僵尸进程是当一个进程在退出过程中, 进程占用的所有资源 (除了 PCB 以及其它一些用于记录进程信息的少量资源外) 都将被回收, 此时进程处于一个只有 task_struct 的状态, 称之为僵尸进程.

之所以会存在僵尸进程, 是因为 PCB 中记录了进程的一些统计信息, 而很多情况下一个子进程的父进程可能会需要这些信息, 故而内核会一直保留该子进程的 PCB 直到它的父进程选择释放或父进程也退出.



X

X : TASK_DEAD - EXIT_DEAD 表示进程即将被销毁. 一些进程在退出时并不会保留它的 PCB, 比如一个多线程程序中被 detach 过的进程, 或者一个进程的父进程通过设置 SIGCHLD 信号的处理器为 SIG_IGN 而显式忽略了 SIGCHLD 信号.

当一个进程进入 X 状态后将意味着它将立刻被彻底释放, 所以 X 状态是非常短暂的.



进程状态的改变

所有的进程都是通过将调用进程复制而得到的子进程. 而调用进程在执行调用时一定是处于 R 状态的, 所以子进程最初也是处于 R 状态的 (除非使用了诸如 CLONE_STOPPED 选项将子进程设为 T 状态).

进程创建以后只存在两个状态转移方向: R → !R or !R → R. 比如向一个处于 S 状态的进程发送 SIG_KILL 信号, 这个进程将先被唤醒为 R 状态, 然后再响应 SIGKILL 而进入 Z / X 状态.

唤醒一个进程是由中断处理程序或其它调用进程将该进程的状态设置为 R 并将它的 PCB 加入到某个 CPU 的可执行队列中来实现的.

posted on 2016-08-12 17:42  妞溜溜  阅读(98)  评论(0)    收藏  举报