• 进程中的任务状态解析


    在 Linux 里面,无论是进程,还是线程,到了内核里面,我们统一都叫任务(Task),由一个统一的结构 task_struct 进行管理。

    每一个任务都应该有一个 ID,作为这个任务的唯一标识。到时候排期啊、下发任务啊等等,都按 ID 来,就不会产生歧义。

    task_struct 里面涉及任务 ID 的,有下面几个:

    1. pid_t pid;
    2. pid_t tgid;
    3. struct task_struct *group_leader;

    所以在内核中,它们虽然都是任务,但是应该加以区分。其中,pid 是 process id,tgid 是 thread group ID。

    任何一个进程,如果只有主线程,那 pid 是自己,tgid 是自己,group_leader 指向的还是自己。

    但是,如果一个进程创建了其他线程,那就会有所变化了。线程有自己的 pid,tgid 就是进程的主线程的 pid,group_leader 指向的就是进程的主线程。

    有了 tgid,我们就知道 tast_struct 代表的是一个进程还是代表一个线程了。

     task_struct 里面关于信号处理的字段。

    1. /* Signal handlers: */
    2. struct signal_struct *signal;
    3. struct sighand_struct *sighand;
    4. sigset_t blocked;
    5. sigset_t real_blocked;
    6. sigset_t saved_sigmask;
    7. struct sigpending pending;
    8. unsigned long sas_ss_sp;
    9. size_t sas_ss_size;
    10. unsigned int sas_ss_flags;

    这里定义了哪些信号被阻塞暂不处理(blocked),哪些信号尚等待处理(pending),哪些信号正在通过信号处理函数进行处理(sighand)。处理的结果可以是忽略,可以是结束进程等等。

    信号处理函数默认使用用户态的函数栈,当然也可以开辟新的栈专门用于信号处理,这就是 sas_ss_xxx 这三个变量的作用。

    state(状态)可以取的值定义在 include/linux/sched.h 头文件中。

    1. /* Used in tsk->state: */
    2. #define TASK_RUNNING 0
    3. #define TASK_INTERRUPTIBLE 1
    4. #define TASK_UNINTERRUPTIBLE 2
    5. #define __TASK_STOPPED 4
    6. #define __TASK_TRACED 8
    7. /* Used in tsk->exit_state: */
    8. #define EXIT_DEAD 16
    9. #define EXIT_ZOMBIE 32
    10. #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
    11. /* Used in tsk->state again: */
    12. #define TASK_DEAD 64
    13. #define TASK_WAKEKILL 128
    14. #define TASK_WAKING 256
    15. #define TASK_PARKED 512
    16. #define TASK_NOLOAD 1024
    17. #define TASK_NEW 2048
    18. #define TASK_STATE_MAX 4096

    TASK_RUNNING 并不是说进程正在运行,而是表示进程在时刻准备运行的状态。当处于这个状态的进程获得时间片的时候,就是在运行中;如果没有获得时间片,就说明它被其他进程抢占了,在等待再次分配时间片。

    在运行中的进程,一旦要进行一些 I/O 操作,需要等待 I/O 完毕,这个时候会释放 CPU,进入睡眠状态。

    在 Linux 中,有两种睡眠状态。一种是 TASK_INTERRUPTIBLE,可中断的睡眠状态。另一种睡眠是 TASK_UNINTERRUPTIBLE,不可中断的睡眠状态。

    这其实是一个比较危险的事情,除非程序员极其有把握,不然还是不要设置成 TASK_UNINTERRUPTIBLE。TASK_KILLABLE,可以终止的新睡眠状态。进程处于这种状态中,它的运行原理类似 TASK_UNINTERRUPTIBLE,只不过可以响应致命信号。

    TASK_STOPPED 是在进程接收到 SIGSTOP、SIGTTIN、SIGTSTP 或者 SIGTTOU 信号之后进入该状态。

    TASK_TRACED 表示进程被 debugger 等进程监视,进程执行被调试程序所停止。当一个进程被另外的进程所监视,每一个信号都会让进程进入该状态。

    一旦一个进程要结束,先进入的是 EXIT_ZOMBIE 状态,但是这个时候它的父进程还没有使用 wait() 等系统调用来获知它的终止信息,此时进程就成了僵尸进程。

    EXIT_DEAD 是进程的最终状态。EXIT_ZOMBIE 和 EXIT_DEAD 也可以用于 exit_state。

    此文章为10月Day23学习笔记,内容来源于极客时间《趣谈Linux操作系统》,推荐该课程。

  • 相关阅读:
    【SpringBoot】生成二维码、在图片中嵌入二维码
    uni-app中返回顶部的方法
    API_String的重要特性
    渐进式 shiro - shiro + jwt+salt (二)
    学习Cmake
    这是什么代码帮我看看
    LeetCode题目笔记——17.19消失的两个数字
    element ui 表格组件与分页组件的二次封装
    这是公司最糟糕的程序员,但是我坚决要留住他!
    Selenium之Webdriver驱动大全【Firefox、Chrome、IE、Edge、Opera、PhantomJS】
  • 原文地址:https://blog.csdn.net/key_3_feng/article/details/133981962