Linux进程基础
2026/3/19 8:56:51 网站建设 项目流程

一、进程与程序:静态与动态的本质区别

初学者易混淆进程与程序,二者从存在形式、生命周期、资源占用等维度存在本质差异,核心是 “静态文件” 与 “动态执行实例” 的区别:

维度程序(Program)进程(Process)
存在形式静态,存储在硬盘中的代码、数据集合动态,程序加载到内存后执行的实例
生命周期永存,除非手动删除文件暂时,有创建、调度、运行、消亡的完整周期
状态变化无状态,始终是静态文件有就绪、运行、阻塞、终止等状态切换
并发特性无并发概念,仅作为文件存在支持并发执行,多进程可抢占 CPU 资源
资源占用不占用系统资源(CPU、内存、文件描述符等)占用 CPU、内存、IO 等系统资源
运行关联一个程序可多次运行,生成多个独立进程一个进程可加载并执行一个或多个程序

直观示例:从代码到进程的转化

test.c(源代码文件) → 编译 → test.out(可执行程序/静态文件) → 运行 → process(进程,分配PID)
  • test.c 是程序的 “源码形态”,存储于硬盘;
  • test.out 是编译后的可执行文件,仍为静态程序;
  • 执行./test.out后,系统为其分配内存、PID,才成为动态运行的进程。

虚拟内存与 MMU:进程隔离的核心保障

Linux 通过虚拟内存和内存管理单元(MMU)实现多进程安全运行:

  • 隔离性:每个进程拥有独立虚拟地址空间,MMU 负责虚拟地址到物理地址的映射,进程间无法直接访问内存,避免篡改;
  • 安全性:内核运行在核心态,进程运行在用户态,进程需通过系统调用(如fork()exit())并经权限校验后才能调用内核功能,防止恶意破坏。

二、进程的分类:按运行特性划分

根据运行方式和交互特性,Linux 进程分为三类,操作系统通过差异化调度策略适配其特性,实现系统并发:

1. 交互式进程

  • 核心特征:运行依赖用户输入,交互性强,执行后返回输出;
  • 典型示例:终端中的vimsshtop,图形界面的浏览器、编辑器;
  • 调度特点:优先保证响应速度,分配更短时间片、更高优先级,避免用户操作卡顿。

2. 批处理进程

  • 核心特征:无需用户实时交互,按预设逻辑批量执行;
  • 典型示例:Shell 脚本、数据库批量备份程序、日志分析脚本;
  • 调度特点:系统负载较低时执行(如夜间),优先级低于交互式进程,避免占用前台资源。

3. 守护进程(Daemon Process)

  • 核心特征:系统启动后自动运行,长期驻留内存,休眠状态下等待触发;
  • 典型示例:nginx/apache(Web 服务)、rsyslogd(日志收集)、系统更新进程;
  • 调度特点:后台常驻,优先级稳定,PPID 通常为 1(由 init 进程接管)。

操作系统的进程状态切换图

linux的进程状态切换图

进程分类的核心价值:实现系统并发

进程分类的本质是优化系统并发能力 —— 操作系统在一段时间内同时运行多个任务的能力:

  • 单 CPU 核心:通过调度器快速切换进程(时间片轮转),宏观上 “同时运行”,微观上同一时刻仅一个进程执行;
  • 多 CPU 核心:升级为并行,多个进程可在不同核心真正同时执行,提升吞吐量。

Linux 针对不同进程的调度优化目标:

  • 保证交互式进程响应速度;
  • 提升批处理进程执行效率;
  • 维持守护进程稳定常驻。

三、父子进程关系:fork () 创建与写时复制机制

Linux 中除 init 进程(PID=1,系统启动时创建)外,所有进程都有且仅有一个父进程,形成树形结构,核心创建方式是fork()系统调用。

3.1 fork () 函数的核心特性

fork()遵循 “一次调用,两次返回” 规则:

  • 调用时,内核为新进程分配 PCB(进程控制块),复制父进程大部分资源;
  • 父进程中,fork()返回子进程 PID(正整数),用于管理子进程;
  • 子进程中,fork()返回 0,可通过getppid()获取父进程 PID;
  • 调用失败(如进程数达上限)返回 -1,并设置errno

3.2 写时复制(Copy-On-Write):高效的内存复用策略

早期fork()会复制父进程全部内存空间(代码段、数据段、堆、栈),若子进程立即执行exec加载新程序,内存复制完全浪费。Linux 2.6 内核后引入写时复制(COW),核心原理:

  • fork()执行后,父子进程共享所有内存页,且标记为 “只读”;
  • 当任意一方修改内存页时,内核为该页创建副本,分配给修改方单独使用;
  • 优势:降低fork()开销,提升进程创建效率,节省内存。

3.3 fork () 代码示例:区分父子进程

#include <stdio.h> #include <unistd.h> #include <sys/types.h> int global_var = 10; // 全局变量,存储在数据段 int main() { pid_t pid; int local_var = 20; // 局部变量,存储在栈 pid = fork(); if (pid == -1) { perror("fork failed"); return 1; } else if (pid > 0) { // 父进程执行逻辑 global_var++; local_var++; printf("父进程 - PID: %d, 子进程PID: %d\n", getpid(), pid); printf("父进程 - global_var: %d, local_var: %d\n", global_var, local_var); sleep(2); // 等待子进程执行完毕 } else { // 子进程执行逻辑 printf("子进程 - PID: %d, 父进程PID: %d\n", getpid(), getppid()); printf("子进程 - global_var: %d, local_var: %d\n", global_var, local_var); // 修改变量,触发写时复制 global_var += 2; local_var += 2; printf("子进程修改后 - global_var: %d, local_var: %d\n", global_var, local_var); } return 0; }

运行结果分析

  • 子进程初始变量与父进程一致(共享内存页);
  • 父进程修改变量不影响子进程,子进程修改时触发 COW,生成独立内存页副本。

四、进程的调度:CPU 资源的分配策略

多进程争夺有限的 CPU 核心资源时,Linux 内核调度器通过合理策略分配 CPU 时间,平衡公平性与响应性。

4.1 调度的核心逻辑:宏观并行与微观串行

  • 宏观并行:通过进程快速切换,用户感知所有进程 “同时运行”;
  • 微观串行:单个 CPU 核心同一时刻仅执行一个进程的指令。

4.2 进程上下文切换

当进程时间片耗尽,内核切换到其他进程运行的过程,核心步骤:

  1. 保存当前进程状态(PCB 标识、寄存器值、程序计数器、内存映射等);
  2. 将状态写入内存,释放 CPU;
  3. 读取待运行进程的状态,恢复到寄存器和 CPU;
  4. 按程序计数器继续执行该进程。

注意:上下文切换存在系统开销,过于频繁会降低整体性能。

4.3 Linux 主流调度算法

调度算法核心逻辑适用场景特点
时间片轮转就绪进程轮流占用 CPU,时间片耗尽触发切换交互式进程保证公平获取 CPU 资源
短任务优先优先调度运行时间更短的进程批处理进程降低整体任务平均等待时间
优先级调度高优先级进程优先获取 CPU响应敏感的实时任务按优先级分配资源
完全公平调度器(CFS)按 “权重” 分配 CPU 时间,权重越高时间片越长内核默认(通用场景)兼顾公平性与响应性
实时调度(SCHED_FIFO/SCHED_RR)先进先出 / 实时进程时间片轮转工业控制、自动驾驶等实时任务优先级高于普通进程,可抢占 CPU

4.4 进程调度相关命令

命令功能说明常用示例
ps aux显示所有进程详细信息(PID、状态、CPU 占用率等)`ps auxgrep nginx`(过滤 nginx 进程)
top实时监控进程资源占用,支持交互式调整优先级P按 CPU 排序,renice调整优先级
kill向进程发送信号,终止 / 调整进程状态kill -9 1234(强制终止 PID=1234 的进程)
killall按进程名批量关闭进程killall -9 a.out(关闭所有 a.out 进程)

总结

进程是 Linux 实现并发的基本单位:

  • 与程序的核心区别是 “动态执行” 与 “静态文件”;
  • 按运行特性分为交互式、批处理、守护进程,适配不同调度策略;
  • fork()是创建进程的核心调用,写时复制优化了内存复用;
  • 调度算法通过平衡公平性与响应性,实现 CPU 资源的高效分配,配套命令可快速管理进程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询