【Linux操作系统】简学深悟启示录:进程初步

发布于:2025-08-05 ⋅ 阅读:(11) ⋅ 点赞:(0)

在操作系统中,进程(Process) 是程序的一次动态执行过程,是系统进行资源分配和调度的基本单位。简单来说,当你运行一个程序(如打开浏览器、启动一个 Python 脚本),操作系统就会创建一个进程,并为其分配内存、CPU 时间等资源,使其能够执行

1.进程先前知识铺垫

1.1 冯诺依曼体系

在这里插入图片描述

如图所示,计算机底层的硬件都要遵守该体系,大致由四部分组成:

  • 输入设备: 鼠标、键盘、摄像头、话筒、硬盘、网卡…
  • 存储器: 简单来说就是内存
  • 输出设备: 显示器、播放器硬件、磁盘、网卡…
  • 中央处理器:CPU,包括运算器和控制器,对我们的数据进行计算任务(算数逻辑),以及流程进行控制

有的设备是纯输入、输出设备,有的既是输出也是输入设备

一个程序要运行,必须先从输入设备进入存储器,到 CPU 处理之后,再回到存储器,由输出设备让我们看到处理结果。该体系规定不能跳过存储器直接与 CPU 交互,简单来说就是所有设备都只能直接和内存打交道

🤔为什么必须按照这种流程?

CPU 的运算速度(纳秒级)远超外部存储设备(如硬盘、U 盘,毫秒级甚至秒级)。存储器的运算速度是适中的,如果没有存储器(尤其是内存)作为 “高速缓冲中转站”,CPU 会被外部设备的慢速拖垮 —— 每次运算都要等外部设备慢吞吞地传输数据,效率会下降几万甚至几十万倍

1.2 操作系统

在这里插入图片描述
操作系统是一款进行软硬件管理的软件,对下通过驱动对硬件进行控制计算的管理,对上提供统一的接口供代码调用

🤔为什么操作系统只提供接口用于调用呢?

操作系统里有各式各样的数据,为了保护数据安全,也为了能给用户提供安全稳定的服务,让所有访问操作系统的行为,通通转化为系统调用完成

🤯操作系统是如何进行管理的?

在这里插入图片描述

先说结论,总结起来就是 “先描述,再组织”,以学校管理学生的入学档案数据为例,每个学生的个人信息就是一份档案,即 struct 结构体节点,将每个节点通过双向链表链接起来,即可以通过增删查改对数据进行管理,这就是操作系统的做法

2.进程

2.1 概念

既然了解了以上知识,那么进程应该是不难理解了,简单来说,进程就是一个已经加载到内存里的程序,叫做进程,也叫任务

每当有一个进程创建的时候,就会对应创建一个 PCBprocess control block)对象,在 LinuxPCB 的具体实现是一个个的 task_structPCB 是描述对象的属性的集合

🚩task_ struct内容分类:

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程
  • 状态: 任务状态,退出代码,退出信号等
  • 优先级: 相对于其他进程的优先级
  • 程序计数器: 程序中即将被执行的下一条指令的地址
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
  • 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图 CPU,寄存器]
  • I/O状态信息: 包括显示的 I/O 请求,分配给进程的 I/O 设备和被进程使用的文件列表
  • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等
  • 其他信息

进程 = 内核 PCB 数据结构对象 + 你自己的代码和数据

2.2 查看进程

在这里插入图片描述

我们将以 process.cpp 这个循环输出的文件为例子查看进程状态(已配置 makefile 文件),下面提到的 PID 表示该进程的 ID 值,PPID 表示该进程的父进程(进程中创建进程后,实行创建的那个进程就叫父进程,被创建的那个就是子进程)

2.2.1 ps用户级工具获取

psLinux 系统中用于查看进程状态的命令,全称是 Process Status。它可以显示当前系统中运行的进程信息,包括进程 ID(PID)、运行状态、CPU 占用率、内存使用等

在这里插入图片描述

  • a:显示所有用户的进程(包括其他用户的进程)
  • j:以作业控制格式显示(包含 PPID 父进程 IDPGID 进程组 IDSID 会话 ID 等字段)
  • x:显示不关联终端的进程(如后台运行的进程、服务进程等)

ps ajx | head -1 && ps ajx | grep ./process 表示查看进程,显示出第一行的信息,并截取 ./process 这一条进程,grep --color=auto ./process 由于 grep 需要高亮显示而创建的进程

可以看到该进程的 PID20662,父进程为 18495

在这里插入图片描述

再去查看对应的父进程,发现是一个名为 bash 的进程。实际上,bash 是当前登录的终端交互系统的进程,大多数命令其直接父进程通常都是当前的 bash

2.2.2 系统文件查看

在这里插入图片描述

根据进程的 PID 同样可以直接在系统目录 proc 下查找到对应进程

2.3 函数获取进程ID

在这里插入图片描述

getpid():用于获取当前调用进程的进程 ID(PID)。这个 PID 常被用于生成唯一的临时文件名等场景
getppid():用于获取当前调用进程的父进程的进程 ID(PPID)

🔥值得注意的是: 使用这两个函数需要包含 <sys/types.h><unistd.h> 这两个头文件,这两个函数总是成功的,不会返回错误

2.4 创建进程

在这里插入图片描述

fork 是用于创建新进程的指令,相当于创建该进程的子进程

当一个进程(称为父进程)调用 fork 时,系统会创建一个新的进程(称为子进程),我们知道 进程 = 内核 PCB 数据结构对象 + 你自己的代码和数据,子进程PCB还是会正常创建一个,但是自定义的数据代码就不一样了。举个例子,子进程和父进程相当于两个厨师,代码相当于菜谱,运行中的代码是不能被修改的,对于父子进程来说是共享的,就不需要再多一份浪费空间;数据相当于食材,虽然做的是同一道菜,但是肯定是两份食材,因为数据可能被修改,不可能共享同一份数据,子进程复制父进程的数据进行的是写时拷贝,只有需要修改的数据才会拿下来拷贝,避免多余的拷贝占用空间

返回值区分: 为什么要创建子进程?是为了让多个进程同时执行不同的事情,因此需要执行不同的代码块,通过 if-else条件句实现。fork 调用会在父进程和子进程中都返回,但返回值不同。在父进程中,fork 返回子进程的 PID;在子进程中,fork 返回 0 。通过判断 fork 的返回值,程序可以区分当前是在父进程还是子进程中执行

运行结果:

在这里插入图片描述

可以看出确实是有两个进程运行着,根据不同的分支的结果就能看出,那么我将提出三个细节上的问题

  1. 为什么fork要给子进程返回0,给父进程返回子进程PID?

子进程被创建后,其自身的 PID 对区分身份来说并非必需 —— 子进程若需要知道自己的 PID,可通过 getpid() 系统调用获取。更重要的是,子进程需要一个明确的信号来识别自己是子进程,而 0 恰好是一个理想的特殊值,因此 0 只作为标识,而不是有效的 PID

父进程创建子进程后,通常需要对其进行后续管理(如等待子进程结束、发送信号、监控状态等),而 PID 是进程的唯一标识,父进程必须知道子进程的 PID 才能执行这些操作

  1. fork函数是如何做到返回两次的?
    在这里插入图片描述

看到 fork 内部的函数结构,中间部分进行相应的子进程创建操作,在 return 操作前子进程就已经创建完毕了,既然 return 也是代码,那么就是共享的,父子进程就都会执行,即 fork 函数会有两次返回

  1. 父子进程谁先运行?

这个是无法确定的,由调度器的策略决定,调度器简单来说就是一个分配进程占据CPU运行效率的组件


希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

请添加图片描述


网站公告

今日签到

点亮在社区的每一天
去签到