进程的概念之进程的状态

发布时间:2024年01月16日
不逼你自己一把,你怎么知道自己行不行

进程状态看看Linux内核怎么说

为了弄明白正在进行的进程是什么意思,究竟怎样才算正在运行的进程,比如说一个人的状态可能在工作也有可能在睡觉,那么我们进程也是也有着运行状态休眠状态。

那么首先我们要知道一个进程可以有几个状态,(在Linux内核中进程有时候也叫做任务)
下面的状态再kerne(包含内核管理的核心代码)l源代码里定义

/*
* 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 */
};
  1. R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列
    里。
  2. S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡((interruptible sleep))。
  3. D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的
    进程通常会等待IO的结束。
  4. T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可
    以通过发送 SIGCONT 信号让进程继续运行。
  5. X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
    我们来挑重点来谈几个状态

首先就是D状态也就是磁盘休眠状态这里的意思其实很简单也就是说在一个进程想要访问某个资源的时候而这些资源却不可用的时候那么该进程就会进入D状态,那么我给大家举一个列子,比如说A进程正在向文件中写入一个很大很大的数据,这时候B进程想要访问该文件可是该文件目前正在被写入数据那么此时B进程就需要先进入磁盘休眠状态来等待该文件的写入完成从而访问该文件。


S状态,s状态也叫做可唤醒睡眠状态那么此时我们就比较容易理解了,他和T状态是有不同的比如说T状态的进程你是不能唤醒的但是S状态的进程是可以被唤醒的比如说父进程创建了一个子进程并等待子进程结束,而子进程进入一个睡眠状态比如说sleep(10)等待10秒钟。在这期间,父进程通过 waitpid 等待子进程的结束。子进程虽然处于S状态,但如果收到信号(例如SIGCHLD),它会被中断并被唤醒。在实际情况中,进程可能会因为等待I/O操作、等待信号、等待锁或其他事件而进入可中断睡眠状态。在这种状态下,如果相应的事件发生或者进程收到中断信号,它就有可能被唤醒。这种状态对于系统的资源管理是很有用的,因为它允许系统更好地处理各个进程的资源需求

代码实列

#include <stdio.h>
#include <unistd.h>
int main() {
    // 创建一个子进程
    pid_t child_pid = fork();
    if (child_pid == -1) {
        perror("Error creating child process");
        return 1;
    }
    if (child_pid == 0) {
        // 子进程在这里执行
        sleep(10);
        return 0;
    } else {
        // 父进程在这里执行
        // 父进程等待子进程结束
        waitpid(child_pid, NULL, 0);
        return 0;
    }
}

T/t状态:这两种状态呢其实到了现在区别已经很少了,T:表示进程被停止,通常是由于接收到了SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU等信号。这种状态意味着进程暂时被挂起,不再执行,等待进一步的命令以继续执行。t:表示进程是一个跟踪进程(traced process)。通常,这是由调试器(如gdb)使用 ptrace 系统调用追踪的进程。被追踪的进程会在收到SIGSTOP信号时进入小写t状态。

进程状态查看

命令:ps aux / ps axj 命令
下面这个图片是进程收到信号的一系列状态
在这里插入图片描述

僵尸进程

  • 僵尸状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
  • 僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
    • 接下来创建一个能维持30s的僵尸进程
    int main()
    {
        pid_t id = fork();    if(id < 0){
            perror("fork");        return 1;    }
        else if(id > 0){ //parent
            printf("parent[%d] is sleeping...\n", getpid());        sleep(30);
        }else{
            printf("child[%d] is begin Z...\n", getpid());
            sleep(5);
            exit(EXIT_SUCCESS);
        }
        return 0;
    }
    

    僵尸进程的危害

    进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
    维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护?是的!
    那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空
    间!
    内存泄漏?是的!

    孤儿进程

    父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?父进程先退出,子进程就称之为“孤儿进程”
    孤儿进程被1号init进程领养,当然要有init进程回收喽。

    int main()
    {
        pid_t id = fork();
        if(id < 0){
            perror("fork");
            return 1;
        }
        else if(id == 0){//child
            printf("I am child, pid : %d\n", getpid());        sleep(10);
        }else{//parent
            printf("I am parent, pid: %d\n", getpid());        sleep(3);
            exit(0);
        }
        return 0;
    }
    

    进程优先级

    cpu资源分配的先后顺序,就是指进程的优先权(priority)。
    优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

文章来源:https://blog.csdn.net/m0_72433000/article/details/134498308
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。