Bootstrap

【Linux】进程状态

一、概念

        我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)

在操作系统原理中:运行状态分为以下三种:运行状态(执行)、阻塞状态、就绪状态

1. 运行状态:

        此状态下是指:进程正在使用CPU执行其指令。

        转换:进程在运行状态下可能会因为时间片用完(时间片用完,但程序还没执行完)或被其他更高优先级的进程抢占而切换到就绪状态。

2.阻塞状态:

        只能由运行状态转换过来,进程在运行到等待某个事件(如I/O操作完成(如等待cin输入)、信号等)时转入阻塞状态。

        转换:当等待的事件发生时,阻塞状态的进程会转换为就绪状态

3.就绪状态:

        进程已准备好执行,但由于CPU被其他进程占用而暂时未被调度。

        转换:当CPU空闲并调度此进程时,它会从就绪状态转换为运行状态。

以上就是在操作系统原理学科中对进程状态的概念。

二、Liunx下的进程状态

        前面章节已经介绍过Linux进程PCB的相关概念,现在可以继续学习PCB中的state成员。

只要是进程就会有对应的进程状态,在Liunx中用task_struct 的state成员来记录进程状态。

struct task_struct {
    pid_t pid;                         // 进程ID
    long state;                        // 进程状态
    unsigned int flags;                // 进程标志
    struct mm_struct *mm;              // 进程的内存管理信息
    struct task_struct *parent;        // 父进程
    struct list_head children;         // 子进程列表
    struct files_struct *files;        // 进程打开的文件信息
    struct fs_struct *fs;              // 文件系统信息
    // 其他字段...
};

Liunx下对应的进程状态,这里我们主要解释一下几个常见的状态。 

static const char * const task_state_array[] = {
    "R (running)",    // 0
    "S (sleeping)",   // 1
    "D (disk sleep)", // 2
    "T (stopped)",    // 4
    "T (tracing stop)", // 8
    "Z (zombie)",     // 16
    "X (dead)"        // 32
    // 其他状态...
};

2.1 "R"运行状态

        在Linux操作系统中,进程的"R"状态表示进程正在运行或准备运行。这意味着进程当前正在使用CPU,或者在就绪队列中等待被调度。

当一个进程处于"R"状态时,它可能正在执行以下操作之一:
1. 正在执行:进程正在CPU上执行其指令。
2. 可运行:进程已经准备好执行,但由于其他进程正在运行,它正在等待调度器给它分配CPU时间。
3. 运行队列中的等待:进程可能因为系统负载较高,导致多个进程竞争CPU时间,因此它在运行队列中等待。

        在Linux中,"R"状态是一种动态状态,进程可以在"R"状态和其他状态(如 "S" 或 "D" )之间切换。例如,一个进程可能会因为等待某些资源(如输入操作完成)而进入睡眠状态,当这些资源变得可用时,进程将被唤醒并返回到 "R" 状态。

【R+】状态:当用ps命令查看进程的状态时,如果进程的状态显示为"R+"

  • R (running): 进程正在运行或可运行。

  • +: 进程是前台进程组的成员。(该进程在前台运行)

前台进程和后台进程

前台进程:

        前台进程是用户当前正在与之交互的进程。它是用户直接控制和输入的进程,通常是在终端(shell)中运行的程序。

        用户可以通过键盘输入与前台进程交互,前台进程的输出会直接显示在用户的终端上。

        用户在终端中运行的文本编辑器、编译器等。

后台进程:

        后台进程是那些启动后不在用户当前工作终端上接收输入和显示输出的进程。后台进程通常用于执行不需要用户交互的任务,例如后台运行编译作业或下载文件。

        运行方法:通过在命令后加上&符号,可以将命令直接以后台方式运行。例如:command &


        在Linux中,每个终端会话都有一个前台进程组,包含一个或多个进程。前台进程组中的进程可以接收来自用户的输入信号(如键盘输入),并且它们的输出会显示在用户的屏幕上。特点:只有前台进程组中的进程才能读取终端输入和向终端写入输出。

2.2 "S" 休眠状态

        进程的"S"状态表示进程正在睡眠(Sleep)(浅度睡眠),进程在等待某个条件或事件(例如I/O操作完成)。在这个状态下,进程不占用CPU资源,处于等待状态。

        当进程调用某个阻塞型系统调用(如read()write()wait()等)时,会进入"S"状态,直到系统调用完成或事件发生。

2.3 "D" 休眠状态(深度)

        进程的"D"状态表示进程深度睡眠(Deep Sleep)(深度睡眠)进程处于不可中断的睡眠状态,通常是在等待一个无法中断的重要I/O操作。这种状态下,进程不能被信号中断。

2.4 "T" 停止状态

        进程已停止,通常是因为接收到停止信号(如SIGSTOP)。进程暂停执行,等待进一步的信号(如SIGCONT)来恢复执行。

        当一个进程接收到'SIGSTOP'、'SIGTSTP'(通常是Ctrl+Z组合键)'SIGTTIN'或'SIGTTOU'信号时(用”kill "命令或系统调用),它将进入" T "状态,处于停止状态的进程暂时不会被执行,但它的资源(如内存和文件描述符)通常仍然被保留

2.4 "Z" 僵尸状态

        Linux操作系统中,进程的" Z "状态表示僵尸状态,在僵尸状态下的进程称为:僵尸进程(Zombie)。进程已终止,但其父进程尚未读取其退出状态。在这种状态下,进程的资源尚未完全释放,仍在进程表中保留一条记录。

要理解僵尸状态,首先要理解下面概念:
1. 进程创建

        每个进程创建:由内核PCB(进程控制块)和进程的代码与数据组成,它们都占据内存空间。

2. 进程退出

        进程退出时,需要释放其PCB、代码和数据所占用的内存空间。退出信息(如退出状态码)会由操作系统写入当前退出进程的PCB中,以供父进程读取。

【退出信息】记录着程序是否正常退出,还是出现异常了。

3. PCB的保留:

        尽管进程的代码和数据空间可以被释放,但PCB不能立即释放,因为父进程或操作系统需要读取进程的退出信息。父进程可以通过调用wait()waitpid()系统调用来读取退出信息。


那么何谓僵尸进程?

僵尸进程

  • 子进程执行完毕并退出,但其父进程未读取其退出状态时,该进程处于僵尸状态。

  • 僵尸进程保留其PCB结构,以便父进程能够读取其退出信息。

  • 僵尸进程的状态为Z,表示它已经终止但仍在进程表中保留记录,直到父进程读取其退出状态。

        通常,父进程应该负责回收其子进程的状态信息。如果父进程没有正确地回收子进程,那么子进程就会进入僵尸状态
        虽然单个僵尸进程对系统的影响很小,但如果系统中存在大量的僵尸进程,它们可能会耗尽进程表的空间(内存泄漏),影响新进程的创建。 

2.5 孤儿进程

        Linux系统中,孤儿进程是指其父进程已经结束,但该进程仍在运行的子进程。当父进程结束后,这些孤儿进程会被"init"进程(在大多数Linux系统中,PID为1)领养,并将孤儿进程的父进程ID(PPID)设置为1。孤儿进程被1号 init 进程领养,也由 init 进程回收,因此孤儿进程不会变成僵尸进程。孤儿进程的管理通常不需要用户干预。

孤儿进程与僵尸进程的区别

  • 孤儿进程:仍在运行的子进程,其父进程已经结束。它们会被系统的"init"进程接管。

  • 僵尸进程:已结束但尚未被其父进程回收的进程(父进程仍在运行)。僵尸进程在进程表中保留了其退出状态,等待父进程通过wait()waitpid()系统调用来读取和清理。

三、进程优先级 

3.1 概念

进程优先级:确定cpu资源分配的先后顺序,就是指进程的优先权(priority)。

  • 进程的优先权决定了进程获得CPU资源的先后顺序。优先权高的进程会比优先权低的进程更早获得CPU时间。

  • 通过设置进程的优先权,可以在多任务环境中优化系统性能,使关键任务优先得到执行。

进程优先级命令: 

ps -la

 

注意到其中的几个重要信息,有下:
UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值(下面详解)

3.2优先级的调整 

Linux进程的优先级 PRI范围:60 ~ 99  (默认)优先级:80
Linux是支持动态优先级调整的,但不运行直接修改PRI的数字,我们通过修改nice值来达到修改优先级目的

nice值:进程优先级的修正数据。

范围是从-20 ~ 19(默认)nice值:0 【其中-20是最高优先级,19是最低优先级。】

优先级计算:

PRI(新) = PRI(old) + nice 

old PRI 每次修改都是从80修改的。

【注意】只有特权用户(通常是root)才能设置负的nice值,从而提高进程的优先级。

;