自学内容网 自学内容网

【Linux】进程状态


在这里插入图片描述

进程状态

一个进程通常有三种状态

◉ 就绪状态(Ready):表示进程已经具备运行所需要的一切条件,只需要等待CPU的分配就可以运行。进程处于就绪状态时,通常会被添加到就绪队列,等待调度器分配CPU资源。

◉ 运行状态(Running):表示进程正在被CPU执行。处于运行状态的进程正在使用CPU进行计算或其他操作。

◉ 阻塞状态(Blocked):表示进程因为某些原因暂时无法继续执行,需要等待一些特定条件的解除之后才能继续运行。例如,当进程等待I/O操作完成或者等待某个资源可用时,会转入阻塞状态。进程在阻塞状态时,通常会被移动到阻塞队列中,等待条件的满足。

 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 */
};

在这里插入图片描述
进程状态实质是结构体task_struct内部的一个属性。通过宏定义的方式进行描述以及更改进程状态。

#define RUN 1
#define SLEEP 2  
#define STOP 3
 
struct task_struct
{
    // 内部的一个属性
    int status;
}
 
struct task_struct process1; //创建进程
process1.status=RUN;//设置进程状态

进程状态的查看

while :; do ps axj | head -1 && ps axj | grep testStatus | grep -v grep; sleep 1;done

R和S运行状态

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

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

通过C语言代码进行验证,依旧使用makefile工具

在这里插入图片描述
我们的进程一直在运行,但是进程状态是S+状态,也就是休眠状态,可是按照我们自己的理解,程序正在运行不应该是R(运行状态)吗?为什么这里是S+状态呢?

printf的本质是往显示器上进行打印;而程序的运行是在千里之外的云服务器上的,最终打印出来的信息显示到我们本地的显示器上;根据冯诺依曼体系结构,显示器是一个外设,所以CPU在跑当前的程序时,把数据写入到我们当前的内存中,打印数据的顺序:先写入到内存里,再刷新到外设这里。可是我们无法保证每次打印的时候,显示器的状态都是就绪的,因为程序是CPU跑的,CPU的运算速度要比显示器本身的速度要快的多,这种快慢人是无法感知的,所以进程在被调度的时候,要访问显示器的资源,因为资源要一直在显示器上打,所以大部分时间,我们的进程一直在等待我们的设备资源是否准备就绪。所以也就是为什么总是S(休眠状态)。

T/t 暂停状态

kill命令

kill [-s <信号名称或者编号>][程序] 或 kill [-l <信息编号>]

功能:给指定命令发信号
常见选项:-l <信息编号> : 若不加<信息编号>选项,则 -l 参数会列出全部的信息名称。

在这里插入图片描述
总共有64个信息编号,其实上面的这些东西都是宏,我们已经会使用 -9 杀死进程,下面我们会用到 -18(SIGCONT)进程继续 以及 -19(SIGSTOP)暂停进程。

上面运行的是T状态,接下来我们来看 t 状态

❍ t (tracing stop) : 当前的进程因为被追踪而暂停了

这种情况可以在调试代码的时候遇见,因为调试的过程,中间就有暂停的动作

④. ./可执行文件 +& —>表示在前台运行。没有+表示在前台。
⑤.x—死亡状态。
⑥.D— 深度睡眠/不可中断睡眠。 D的存在主要是保护重要进程不被干掉。如果非要中断有两种情况:断点重启和等待进程结束。

进程的运行、阻塞和挂起

运行
(1).进程运行时一定是在cpu上运行。每一个cpu都需要维护一个运行队列(数据结构)。
(2).进程在运行队列中,该进程的状态就是R状态(运行状态)。
(3).进程是基于时间片进程轮转调度的。让多个进程以切换的方式进行调度,在一个时间段内同时得以推进代码,这就叫做并发。

阻塞
我们C语言中的scanf在等待你输入是属于什么状态呢?暂停吗?
答:是阻塞状态,S属于阻塞状态。等待某资源是都就绪。

(1).不止有CPU才有运行队列,各个设备也有自己的等待队列。
(2).阻塞指一个进程从进程队列里剥离下来,列到其他设备的队列里。
(3).当阻塞结束,把进程从其他设备的队列,在列会进程队列中交唤醒。

挂起状态:
(1).挂起就是将操作系统的暂时不用的进程,交换到磁盘中swap区。你在需要调度的时候,在换出。
(2).频繁地换入换出会导致效率问题。

僵尸状态

僵尸状态:当一个 Linux 中的进程退出的时候,一般不会直接进入 X 状态(死亡,资源可以立马被回收),而是进入 Z 状态。如果父进程不对其进行回收,则会一直处于僵尸状态,也就是子进程先于父进程退出。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int main() {
    pid_t id = fork();
    if (id < 0) {
        perror("fork");
        return 1;
    } else if (id == 0) { // 子进程
        printf("子进程[%d]开始运行...\n", getpid());
        sleep(5);
        printf("子进程[%d]退出...\n", getpid());
        exit(0);
    } else { // 父进程
        printf("父进程[%d]正在睡眠...\n", getpid());
        sleep(15); // 父进程延迟回收子进程
    }
    return 0;
}

为什么父进程不回收子进程PCB?

1.父进程要知道子进程为什么要退出,父进程要获取子进程退出的信息。

2.独立性,父进程只读取子进程的信息,不对信息做修改,依旧保持独立性。

僵尸进程的危害

僵尸进程虽然不再运行,但它们仍然占用系统资源(如进程控制块task_struct)。如果父进程不及时回收子进程,会导致系统资源浪费,甚至内存泄漏。

避免僵尸进程

可以通过以下方式:

1️⃣ 父进程及时调用wait()或waitpid()回收子进程。

2️⃣ 使用信号处理机制,在子进程退出时通知父进程进行回收。


原文地址:https://blog.csdn.net/Lehjy/article/details/142905824

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!