Linux 线程的状态

通常的操作系统概念里, 都会区分进程和线程, 可是在 Linux 内核里面, 对于系统调度来说, 它不区分进程和线程, 统一的术语都是线程(Thread), 线程做为调度的基本单位.

对于一个系统来说, 硬件的处理器(CPU)个数(插槽数), 一个 CPU 上的核(core)的数量, 一个核上的硬件线程数(Hyper-Thread)数都是有限的. 有的线程正在 CPU 上运行(on-cpu), 有的不在 CPU 上运行(off-cpu). 那么对于 Thread 来说, 它有哪些状态呢?

通常我们会在 Linux 上面看到这些状态:
• Runnable state 可运行状态,正在 CPU 运行或在队列等待运行
• Sleeping state 等待 I/O 或 调用 sleep 函数 响应 其它 interrupt
• Uninterruptable sleep state 等待 I/O 不响应其它 interrupt
• Defunct or Zombie state 等待父线程/root 线程 ack 死亡

为什么会有僵尸(Zombie)状态?
每个进程运行结束之后, 会返回一个状态码, 本身结束运行之后, 进入 Zombie 状态, 然后创建它的父进程(除了 1 号进程没有父进程)收到这个状态码, 做个响应, 它就可以正常死亡了. 如果它的父进程一直没时间响应, 它就会一直停留在 Zombie 状态. 如果某个进程的父进程早就自己死亡了, 那么 1 号进程就会作为它的父进程进行响应.

如果在 ps 命令下, 我们能看到稍多状态:

D    uninterruptible sleep (usually IO)
I    Idle kernel thread
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
X    dead (should never be seen)
Z    defunct ("zombie") process, terminated but not reaped by its parent

对于 ps 命令, 这些状态从哪里获得?
从 /proc/<pid>/task/<pid>/status 得到, 比如:

supra@suprabox:/proc/3119/task/3125$ cat /proc/3119/task/3125/status
Name:    gmain
Umask:    0002
State:    S (sleeping)
Tgid:    3119

对于 sleep 的线程, 它到底从哪个函数进入的 sleep?
通过 cat /proc/<pid>/task/<pid>/wchan 可获得(wchan: waiting channel), 比如:

cat /proc/3119/task/3125/wchan
poll_schedule_timeout.constprop.13

进入 sleep (S & D) 状态的线程, Scheduler 不会再给他们安排 CPU 执行它们的代码. 当线程进入 sleep 之前, 它会进入内核态, 更新它自己在内核的里面 scheduler 数据结构的状态, 告诉内核scheduler 把自己从等待执行的队列中放到一个等待队列中. 当自己等待的信号(I/O interrupt 或者 sleep的时间到), 内核处理 interrupt 的内核进程会重新把它们放到认为等待执行队列. 于是它们重新获得执行机会.

标签: none

添加新评论