什么是进程?

  • 进程是一个正在运行的程序,是加载到内存中的程序实体。

  • 进程与程序相比,具有动态属性。

进程先描述后组织,即进程是先通过进程控制块(PCB)描述,再由操作系统组织和管理的。

PCB 概念 (进程控制块)

PCB(进程控制块)是操作系统中用来描述进程的基本结构,用来存储进程的所有属性。

struct task_struct {
    // 该进程的所有属性
    // 该进程对应的代码地址和属性地址
};

task_struct 是内核结构体,表示一个内核对象,它将代码和数据与具体的进程关联起来。内核通过 task_struct 管理进程,即通过 PCB 将进程信息与内存中的代码关联,实现进程的组织和调度。

Linux 查看进程的方式

常见的系统进程查看方式

在 Linux 中,命令行上的进程的父进程通常是 bash。可以通过系统调用函数来查看进程:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
​
int main() {
    while(1) {
        printf("%d\n", getpid());
    }
    return 0;
}

常见的用于查看父进程的系统调用是 getppid()

printf("%d\n", getppid());

另外,通过查看 /proc 文件目录也可以查看当前进程的详细信息。

image-20240910151424004

fork 初识

fork() 是创建子进程的系统调用,返回两个值:父进程返回子进程的 PID,子进程返回 0。父子进程共享代码,但数据独立,各自拥有自己的空间。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
​
int main() {
    fork();
    printf("%d -- | -- %d\n", getpid(), getppid());
    return 0;
}

运行效果如下:

chen@chen:~$ ./test
13977 -- | -- 13667
13978 -- | -- 13977

其中 13667 是 bash 进程。

进程状态

进程的状态包括:运行、新建、就绪、挂起、阻塞、等待、停止、死亡。

进程的状态会影响操作系统的调度和管理。一个 CPU 只有一个运行队列,所有进程都需要排队等待 CPU 资源。

static const char * const task_state_array[] = {
    "R (running)",       // 运行状态
    "S (sleeping)",      // 浅度睡眠
    "D (disk sleep)",    // 深度睡眠
    "T (stopped)",       // 停止
    "t (tracing stop)",  // 跟踪状态
    "X (dead)",          // 死亡
    "Z (zombie)"         // 僵尸状态
};
  • 运行状态:被调度并处于运行队列的进程。

  • 阻塞状态:等待外设响应的进程。

  • 挂起状态:进程数据与代码被交换到外部设备,暂时被挂起。

深度睡眠的进程无法被操作系统直接杀掉,除非断电或等待系统自动恢复。

使用命令 ps axj | head -1 && ps -axj | grep bash 可以查看进程状态。

chen@chen:~$ ps axj | head -1 && ps -axj | grep bash
PPID   PID   PGID   SID TTY     TPGID STAT  UID  TIME COMMAND 
15572  15707  15706  15572 pts/0    15706 S+    1000  0:00 bash

S+ 中的 + 表示前台进程,若无 + 则表示后台进程。

僵尸状态 (Z):子进程退出后,父进程未读取其状态,子进程进入僵尸状态。

孤儿进程:父进程退出后,孤儿进程被 init 进程(PID 1)收养。

进程的优先级

什么是优先级?

进程优先级用于决定任务的调度顺序,某些任务需要优先执行。

Linux 的优先级机制

在 Linux 中,进程的优先级由两个数值决定:PRI 和 NI。PRI 是基本优先级,NI 是 Nice 值。

优先级 = 老的优先级 + NICE

Nice 值的取值范围是 [-20, 19],Nice 值越低,优先级越高。可以使用 top 命令,按 R 键修改优先级。

进程的特性

  • 竞争性:根据优先级高效完成任务。

  • 独立性:多个进程独享资源,互不干扰。

  • 并行:多个进程在多个 CPU 上同时运行。

  • 并发:在一个 CPU 上通过进程切换,在同一段时间内推动多个进程。

进程切换

进程切换时需要保存和恢复进程的上下文。操作系统会在不同进程之间进行切换,保证每个进程的上下文信息正确保存和恢复。