来聊聊进程(一)
LI Rui

什么是进程?一句话:进程是资源分配的最小单位。进程属于操作系统“虚拟化”的工作之一,操作系统将CPU给虚拟化,使得不同进程能够产生独享CPU的“幻觉”。

之后的一系列文章会陆陆续续剖析进程的数据结构以及进程是怎么被创建和执行的,今天我们先来看Linux中进程的状态。


Linux中进程的状态

对应源码文件:include/linux/sched.h

在Linux 5.15的代码中,涉及进程和程序的算法围绕着一个名为task_struct的结构体展开。这个结构体的代码截至目前一共有接近800行,包含了pid、调度信息、父子进程关系、栈canary等信息,他们有的是直接将值保存到结构体中,有的是通过指针的方式指向一个新的结构体。下面让我们对表示进程状态的两个成员进行剖析:

__state

在源码文件的头部,我们可以看到以下定义的常量:

1
2
3
4
5
6
7
8
9
10
11
#define TASK_RUNNING			0x0000
#define TASK_INTERRUPTIBLE 0x0001
#define TASK_UNINTERRUPTIBLE 0x0002
#define __TASK_STOPPED 0x0004
#define __TASK_TRACED 0x0008
#define TASK_PARKED 0x0040
#define TASK_DEAD 0x0080
#define TASK_WAKEKILL 0x0100
#define TASK_WAKING 0x0200
#define TASK_NOLOAD 0x0400
#define TASK_NEW 0x0800

对他们的解释如下:

  • TASK_RUNNING 进程处于可运行状态,但可能并未被分配CPU,正等待被调度。

  • TASK_INTERRUPTIBLE 进程处于等待某事件或资源的队伍中,如果内核发送信号表示事件已经发生后,进程状态会立即变为TASK_RUNNING。

  • TASK_UNINTERRUPTIBLE 表示不能由外部信号唤醒的状态,表示因内核指示睡眠的进程。

  • __TASK_STOPPED 表示进程特意停止。

  • __TASK_TRACED 本身不属于进程状态,用于表示被调试的进程,这些进程只能由调试进程通过系统调用唤醒。

  • TASK_PARKED 进程处于被阻塞的状态。

  • TASK_DEAD 进程处于退出状态,将被销毁。

  • TASK_WAKEKILL 与TASK_UNINTERRUPTIBLE不同的是,这个状态的进程能够被致命信号唤醒。

  • TASK_WAKING 表示进程正在被某“人”唤醒,其他尝试唤醒该进程的操作将失败。sched: Add TASK_WAKING

  • TASK_NOLOAD 与TASK_UNINTERRUPTIBLE合并使用,使得loadavg计算时忽略该进程。[PATCH] sched: Introduce TASK_NOLOAD and TASK_IDLE

  • TASK_NEW 初始化进程信息时,状态会被设置为该值。

exit_state

exit_state成员的可能取值如下:

1
2
#define EXIT_DEAD			0x0010
#define EXIT_ZOMBIE 0x0020
  • EXIT_DEAD 表示父进程已经调用了wait,即正等待子进程退出的状态。
  • EXIT_ZOMBIE 子进程结束后的状态。

exit_state明确地表示了进程的退出。


下一篇文章我们将介绍Linux中进程相关的API。

参考资料

  • Linux 5.15源码
  • 《深入理解Linux内核架构》
  • 本文标题:来聊聊进程(一)
  • 本文作者:LI Rui
  • 创建时间:2021-12-26 18:59:12
  • 本文链接:https://www.lirui.tech/post/2021/8e4c6a2980ef.html
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-SA 许可协议。转载请注明出处!