【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

07-17 971阅读

目录

        操作系统中

运行状态

阻塞状态

进程状态转换

 Linux系统中

查看进程状态

深度睡眠状态

T 暂停状态

Z 僵尸状态

 孤儿状态

文章手稿


xmind: 

【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

文章手稿可见文末 

引言

介绍系统中的进程状态及其管理方式。将通过结合操作系统原理和实际代码示例,详细说明进程的各种状态、转换过程以及处理方法。

操作系统中

一个进程通常有三种状态

  • 就绪状态(Ready):表示进程已经具备运行所需要的一切条件,只需要等待CPU的分配就可以运行。进程处于就绪状态时,通常会被添加到就绪队列,等待调度器分配CPU资源。
  • 运行状态(Running):表示进程正在被CPU执行。处于运行状态的进程正在使用CPU进行计算或其他操作。
  • 阻塞状态(Blocked):表示进程因为某些原因暂时无法继续执行,需要等待一些特定条件的解除之后才能继续运行。例如,当进程等待I/O操作完成或者等待某个资源可用时,会转入阻塞状态。进程在阻塞状态时,通常会被移动到阻塞队列中,等待条件的满足。

    我们下面将对运行,阻塞,和阻塞挂起进行介绍~ 

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    运行状态

     进程只要在运行队列中,就叫做 运行态。

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    阻塞状态

    关于进程:

    ① 一个进程使用资源的时候,可不仅仅是在申请 CPU 资源

    ② 进程可能会申请其它资源:磁盘、网卡、显卡,显示器资源……

    如果我们申请 CPU 资源无法暂时无法得到满足,这就需要排队的 "运行队列" 。那么如果我们申请其他慢设备的资源呢?是需要排队的(task_struct 在进程排队)。

    当访问某些资源(磁盘,网卡等),如果该资源暂时没有准备好,或者正在给其他进程提供服务,那么此时:

    ① 当前进程要从 runqueue 中逐出。

    ② 将当前进程放入对应设备的描述结构体中的waitqueue 。

    进程状态:看PCB在哪个队列

    内存不足了,操作系统就会把 该进程的代码和数据置换到磁盘上,进行 进程挂起。

    进程状态转换

    进程状态的转换可以通过以下示例说明:

    #include 
    #include 
    int main() {
        while (1) {
            printf("进程[%d]正在运行...\n", getpid());
            sleep(1); // 模拟阻塞状态
        }
        return 0;
    }
    

    通过运行上述代码并观察进程状态,可以理解进程在不同状态之间的转换过程。

    三种状态的图示如下:

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态


     Linux系统中

    进程状态用整数表示,这些整数存储在进程的task_struct结构体中。常见的进程状态包括:运行(R)、睡眠(S)、磁盘睡眠(D)、停止(T)、死亡(X)、僵尸(Z)和孤儿进程。

    进程状态一览

    状态代码状态名称描述
    R运行(Running)进程正在运行或在运行队列中等待
    S睡眠(Sleeping)进程在等待某事件完成,可被信号唤醒
    D磁盘睡眠(Disk Sleep)进程在等待I/O操作完成,不可被信号唤醒
    T停止(Stopped)进程被暂停,可通过信号恢复
    X死亡(Dead)进程已终止,从进程列表中移除
    Z僵尸(Zombie)进程已退出,父进程尚未读取其状态
    孤儿(Orphan)父进程已退出,被init进程收养

    查看进程状态

    使用ps aux或ps axj命令可以查看系统中进程的状态。例如:

    ps aux
    ps axj
    

    这些命令输出的状态字段展示了进程当前的状态。

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    背后的原因让人暖心,cpu太快了,print显示器等待的时间在他看来就是在sleep了

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    深度睡眠状态

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    这个D状态我们就不模拟了……可能会把我的机子磁盘打满(害怕.dog) 


    T 暂停状态

    比如看视频,听音乐,下载,都会有暂停。当你点击暂停的时候下载对应的代码就不跑了,此时这个进程你就可以认为是暂停状态。

    再比如说我们调试程序,让程序打断点之后让程序运行起来,程序在打断点处停住的时候是将进程暂停了,所以你在gdb 调试或在 VS 下调试时你会发现程序会停下来,这就是暂停。

    是进程挂起的一种。

    我们可以先来看一下kill

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    接下来可以来尝试一下;

    $ kill -19 4026,就会发现

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    gdb下的暂停状态,测试一下

    $ gdb process  # 进入gdb调试
    (gdb) l        # 查看代码
    (gdb) b 9      # 打断点
    q + 回车       # 退出

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    Z 僵尸状态

    僵尸状态:当一个 Linux 中的进程退出的时候,一般不会直接进入 X  状态(死亡,资源可以立马被回收),而是进入 Z 状态。

    为什么呢~

    进程为 Z 状态,就是为了维护退出信息,可以让父进程或者 OS 读取记录的,退出信息会写入 test_struct。

    以下是创建僵尸进程的代码示例:

    #include 
    #include 
    #include 
    int main() {
        pid_t id = fork();
        if (id  
    

     我们可以写一个监控脚本来看一下~

    while :; do ps axj | head -1 && ps axj | grep mytest | grep -v grep; sleep 1; echo "######" ; done

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    在另一个终端中运行ps命令可以看到子进程进入僵尸状态。

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    僵尸进程的危害

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

    避免僵尸进程

    可以通过以下方式:

    1. 父进程及时调用wait()或waitpid()回收子进程。
    2. 使用信号处理机制,在子进程退出时通知父进程进行回收。

     孤儿状态

    孤儿进程:父亲没了(bushi

    即:父进程先退出了,子的父就变成1 号进程了,相当于被os领养了

    测试一下:

    #include 
    #include 
    #include 
     
    int main(void) {
        pid_t id = fork();
        if (id == 0) {
            // child
            int cnt = 5;
            while (1) {  // 死循环,孩子进程就不退了
                printf("我是子进程,我还剩下 %ds\n", cnt--);
                sleep(1);
            }
            printf("我是子进程,我已经变僵尸了,等待被检测\n");
            exit(0);
        }
        else {
            // father
            int cnt = 3;
            while (cnt) {
                printf("我是父进程,我: %d\n", cnt--);
                sleep(1);
            }
            exit(0);
        }
    }

     监控一下:

     while :; do ps axj | head -1 && ps axj | grep mytest | grep -v grep; sleep 1;echo "######";done
    

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    我们可以top看一下1究竟是什么

    【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

    ❓ 疑问:父进程退出,为什么父进程没有变成僵尸?我们怎么没有看到父进程 为Z  ?

    • 那是因为父进程的父进程是bash ,它会自动回收它的子进程,也就是这里的父进程。这里之所以没有看到父进程变成僵尸,是因为被 bash 回收了, z->x 的状态很快,所以你没看到。
    • 那为什么刚才我自己代码中的父进程创建的子进程,父进程没有回收子进程呢?那是因为你的代码压根就没有写回收,所以你的子进程就没有回收。

      那我们怎么暂停呢,ctrl+c 只能干掉前台进程,

      所以孤儿进程就要用到我们的杀进程:kill -9来暂停啦

      【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态


      文章手稿

      【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

      【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]