【进程概念】进程状态以及僵尸进程(结合代码)

简介: 【进程概念】进程状态以及僵尸进程(结合代码)

进程状态

进程状态的概念

进程状态反映进程执行过程的变化。这些状态随着进程的执行和外界条件的变化而转换

而在task_struct里,其实也就是用一些变量来表示进程状态,其中state表示的就是进程的当前状态,state定义在 Linux 源文件 include/linux/sched.h 头文件中.-1 就表示不能运行,0表示运行,大于0表示停止。

 volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
 int exit_state;
 unsigned int flags;

观察kernel源代码里是怎么描述进程状态的

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列

里。

S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。

D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

Z僵尸状态(zombie):当进程退出且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程

实验观察进程的各个状态

动态监视进程的脚本

为了方便实时观察进程的状态,我们可以新开一个窗口使用一个动态监视的脚本来观察:

while :; do ps ajx|head -1 && ps ajx|grep test | grep -v grep;sleep 1; done

ps ajx|head -1的意思就是打印进程信息的头部状态栏属性

ps ajx|grep test | grep -v grep 显式包含test的进程的信息,并过滤掉grep指令本身这个进程

while :;do 指令 ; sleep 1 done循换while中的指令,每过一秒执行一次

代码样本1:观察S(浅度睡眠)状态

运行程序并执行脚本观察

以上结果很奇怪,在右边的窗口中,test程序一直在printf打印,可是为什么进程的状态显示是S休眠状态呢?(S+中的’+‘表示该进程在前台运行,运行时加一个&就可以使程序在后台运行)

原因是CPU的处理速度太快了,每次程序在申请打印资源的时候都需要等待。相对cpu来说,等待这个过程的时间是漫长的。而等待成功后向屏幕打印这个动作几乎是瞬间的,马上就又要去等待。所以在我们的监测脚本看来,好像一直处于休眠状态,其本质原因在于CPU的运算速度比显示器这个外设的运算速度要快得多。所以我们大概率只能看到休眠状态。

由此我们也能理解,休眠状态其实就是在等待“资源”就绪。

此外,我们能用ctrl+c能够强行终止一个在休眠的进程,这样的休眠状态也叫可中断休眠(浅度睡眠)

代码样本2:观察R(运行)状态

运行程序并执行脚本观察,R状态

果然,将打印代码注释掉之后,我们就能看到进程的运行状态R

发送kill -19 信号 观察T(暂停)状态:

kill -l查看信号

发送信号暂停某个进程,继续运行代码样本2:

格式是 kill + 信号编号+进程pid

再发送kill -18 26187唤醒被暂停的进程,于是test进程的状态由T变成了R

T状态时,程序处于暂停状态,此时信息没有任何更新,是完全的暂停。处于S状态的进程会有一些数据更新,比如睡眠了多少秒等

那么t状态和T状态有区别吗?

答案是有的。

调试代码,观察t(追踪)状态

t状态表示跟踪状态,这个状态有点特殊,常在调试中遇见:

当我们打好断点进行调试,程序在遇到断点处就会暂停变为追踪状态。此时的进程在等待gdb进程对他进行操作。

和T状态不同的是,t状态不能被kill -18 信号唤醒, 只能等到调试进程通过ptrace系统调用执行PTRACE_CONT、PTRACE_DETACH等操作 (通过ptrace系统调用的参数指定操作), 或调试进程退出,被调试的进程才能恢复R状态。

X(死亡)状态

表示一个进程死亡,CPU会进行资源的回收。由于这个状态比较瞬时,难以观察到。

D(深度睡眠)状态

D(disk sleep),深度睡眠状态,又叫不可中断睡眠状态。跟S状态类似,都是在休眠等待”资源“,但是D状态不能被中断。也就意味着用kill发送中断信号对它也没用。一旦进入了D状态,就只能被资源唤醒(或者重启、断电)。

Z状态(僵尸进程)

Z状态又叫僵尸状态。表示一个终止了但是还未被回收的进程的状态

当一个进程由于某种原因终止时,内核斌并不是立即把他从系统中清除。相反,进程被保持在一种已终止的状态中,知道被父进程回收。当父进程回收已终止的子进程时,内核就会把子进程的退出状态传递给父进程,然后抛弃已经终止的进程,这个时候子进程就不存在了。

为什么已经终止的子进程被称为僵尸进程?

在民间的传说中,僵尸是活着的尸体,一种半生半死的实体。而僵尸进程已经终止了,内核还在保留着他的退出信息知道父进程回收为止,与僵尸类似。

给出以下代码观察僵尸状态

运行脚本监测

观察代码我们可以知道,子进程被创建后休眠五秒后马上就return;此时的子进程已经被终止,但是并没有马上释放所有资源,而是等待父进程的回收。父进程这个时候陷入了较长的休眠状态,并没有马上回收子进程。于是导致了子进程称为了僵尸进程。如果没有父进程去处理这些退出信息,僵尸进程就会一直存在,其部分未释放的资源也一直存在。也就造成了内存泄漏。

孤儿进程

与僵尸进程相反,如果父进程先终止,那该父进程的子进程就会成为孤儿进程。

成为孤儿进程后,内核会安排init进程成为它的孤儿进程的养父。init进程的PID为1,是在系统启动的时候由内核创建的,他不会终止,是所有进程的祖先。如果父进程还没来得及回收僵尸子进程就终止了,init进程也会去回收它们。不过长时间运行的程序,比如shell或者服务器,总是应该回收它们的僵尸子进程。即使僵尸子进程没有运行,它们也消耗内存资源。

观察以下代码

当父进程终止,子进程成为孤儿进程,被init领养

进程的五态模型

上面的七种进程状态可以总结为三种:运行、阻塞、挂起。

是不是非常熟悉呢,这就是我们教科书上经常看到描述进程状态的三种状态。

其中运行态R分为两个部分:

一个是真正在CPU中执行的进程状态(运行态)

一个是在CPU的运行队列中但是还没有进入CPU的进程状态(就绪态)

这两种状态都可以被称为运行态。

挂起状态通常发生在内存不足的情况下,系统会将暂时用不到的一部分进程资源换出到磁盘里面,此时进程状态为S,等内存不在那么紧张的时候再唤醒该进程,并重新将资源加载到内存里面。整个过程比较消耗时间,是一种用时间换空间的做法。

相关文章
|
9月前
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
6月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
131 20
|
5月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
111 0
|
5月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
117 0
|
8月前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
283 4
|
8月前
|
存储 算法 数据处理
进程基础:概念、状态与生命周期
进程是操作系统进行资源分配和调度的基本单位,由程序段、数据段和进程控制块(PCB)组成。线程是进程中更小的执行单元,能独立运行且共享进程资源,具有轻量级和并发性特点。进程状态包括就绪、运行和阻塞,其生命周期分为创建、就绪、运行、阻塞和终止阶段。
462 2
|
11月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
414 4
|
Linux C++
Linux c/c++进程之僵尸进程和守护进程
这篇文章介绍了Linux系统中僵尸进程和守护进程的概念、产生原因、解决方法以及如何创建守护进程。
287 0
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
190 1
|
Linux Shell 调度
【在Linux世界中追寻伟大的One Piece】Linux进程概念
【在Linux世界中追寻伟大的One Piece】Linux进程概念
181 1