1、进程和线程
1.1 进程基本概念
- 程序: 存放在硬盘中的静态指令和数据集合,无执行状态。
- 进程: 是程序的动态执行实例(动态执行的过程) ,包括创建、调度、消亡的整个过程;由内核管理,包含独立的地址空间、PCB(进程控制块)、文件描述符表等,是操作系统资源分配的最小单位。
1.2 进程相关命令
1.2.1 top
- 作用 :动态实时查看所有进程任务信息,按 CPU / 内存占用率排序
- 核心字段 :
- PID:进程唯一 ID(值 > 0)
- PPID:父进程 ID
- % CPU:进程占用 CPU 百分比
- % MEM:进程占用内存百分比
- COMMAND:进程对应的命令 / 程序名
- 常用操作: 按
P按 CPU 排序、按M按内存排序、按q退出
如下图所示:

1.2.2 ps -ef
- 作用 :查看当前系统中所有进程任务的完整信息(标准格式,包含 UID、PPID 等)
- 格式解读 :
- UID:进程所属用户 ID
- PID:进程 ID
- PPID:父进程 ID
- C:CPU 占用率
- STIME:进程启动时间
- TTY:进程关联的终端(? 表示无终端)
- TIME:进程占用 CPU 总时间
- CMD:进程命令
- 实用用法 :
ps -ef | grep 进程名------ 过滤查找指定进程(注意: grep 自身会匹配出一条,可加| grep -v grep排除)
如下图所示:

1.2.3 ps -aux
- 作用 :查看进程信息(进程状态)
- 核心字段 :
- USER:进程所属用户
- PID:进程 ID
- % CPU:CPU 占用百分比
- % MEM:内存占用百分比
- VSZ:虚拟内存大小(KB)
- RSS:物理内存占用(KB)
- STAT:进程状态(R 运行、S 睡眠、Z 僵尸、T 停止等)
- COMMAND:进程命令
- 实用用法 :
ps -aux | grep 进程名------ 比 ps -ef 更直观看到资源占用
如下图所示:

1.2.4 kill
- 作用:向进程发送信号,实现终止 / 暂停等操作(默认发送 15 号终止信号,-9 为强制杀死)
- 常用用法 :
kill 进程PID:发送 15 号信号(SIGTERM),让进程优雅退出(可被进程自身忽略)kill -9 进程PID:发送 9 号信号(SIGKILL),强制杀死进程(无法忽略,慎用)killall -9 进程名:按进程名强制杀死所有同名进程
1.2.5 &
- 作用 :执行命令时,将任务放到后台运行(终端可继续输入其他命令)
- 用法 :
./a.out & - 注意:后台进程仍与当前终端关联,终端关闭则进程可能终止
1.2.6 ps
- 作用 :查看当前终端下由当前用户启动的所有前后台进程(不含完整信息)
- 补充 :
ps -l可查看当前终端进程的详细信息(含优先级、状态等)
如下图所示:

1.2.7 jobs
- 作用 :查看当前终端下的所有后台 / 暂停任务,并显示任务编号(%1、%2...)
- 核心字段 :
- 任务编号:如 [1]、[2]
- 状态:Running(运行)、Stopped(暂停)
- 命令:任务对应的命令
- 用法 :直接输入
jobs即可,常用参数jobs -l可同时显示进程 PID
1.2.8 fg 编号
- 作用 :将后台运行 / 暂停的任务调至前台执行
- 用法 :
fg 1或fg %1:将编号 1 的后台任务调到前台- 若只有一个后台任务,直接
fg即可(无需编号)
1.2.9 nice
- 作用 :启动进程时指定其优先级(Linux 优先级范围:-20(最高) ~ 19(最低),默认 0)
- 用法 :
nice -n 优先级 命令- 例:
nice -n 10 ./a.out------ 以优先级 10 启动 a.out(更低优先级,占用 CPU 更少) - 例:
nice -n -5 ./a.out------ 以优先级 - 5 启动(更高优先级,需 root 权限)
- 例:
- 注意:普通用户只能设置 0~19,负优先级(-20~-1)需 root 权限
1.2.10 renice
- 作用 :修改正在运行的进程的优先级
- 用法 :
renice -n 优先级 进程PID- 例:
renice -n 5 12345------ 将 PID 为 12345 的进程优先级改为 5
- 例:
- 注意 :
- 普通用户只能调高自身进程的优先级(如从 0→5),不能调低;root 可任意修改
- 优先级范围同 nice:-20 ~ 19
1.3 进程的创建
虚拟地址:MMU(内存管理单元)将物理地址映射后的可以访问的地址空间
物理地址:硬件RAM的实际空间地址,用户一般不允许直接访问物理地址,要通过MMU映射为虚拟地址再进行访问
虚拟地址空间分布:
每个进程执行,操作系统会为进程分配0-4G虚拟内存空间
0-3G(用户空间) 3-4G(内核空间)
- 文本段(.text):只读,存放代码和相关指令
- 数据段:
- 存放字符串常量(.rodata)
- 已初始化全局/静态变量(.data):在编译时分配空间,程序运行时加载到内存空间中
- 未初始化全局/静态变量(.bss):(编译时不占空间,运行时分配并初始化为 0)在进程启动后由进程默认初始化为0值
- 栈区(.stack):默认8M,存放局部变量、函数参数、返回地址,未经初始化值为随机值,超过变量作用域自动回收变量空间,增长方向自高向低增长
- 堆区(.heap):剩余的空间为堆区,可以由程序员手动申请释放,增长方向自低向高增长
- 内核:所有进程共享,存放内核代码 / 数据,用户无法访问
1.4 多个进程的空间(进程空间是独立的)
- 每个进程都有独立的 0~4G 虚拟地址空间 (虚拟地址值可重复),MMU 会将不同进程的虚拟地址映射到不同的物理地址空间。
- 例:进程 1 和进程 2 的虚拟地址 0x1000,MMU 会映射到物理内存的不同位置(如 0x80000000 和 0x90000000),保证进程间内存隔离。
- 多进程共用同一虚拟地址空间,但物理是独立的

1.5 进程的调度
- 核心原则:操作系统内核的进程调度器负责分配 CPU 资源,目标是 "公平 + 高效利用 CPU"。
- 核心特点:宏观并行(用户看多个进程同时运行),微观串行(CPU 核心同一时间只执行一个进程)。
- 常见调度算法 :
- 先来先服务(FCFS)(先来先执行,后来后执行):按进程到达顺序调度,优点简单,缺点 "饥饿"(长进程阻塞短进程)。
- 短作业优先(SJF):优先调度运行时间短的进程,减少平均等待时间,缺点 "长作业饥饿"、需预估作业时长。
- 高优先级调度:优先级高的进程先执行(Linux 优先级:-20 最高,19 最低),分为:
- 非抢占式:高优先级进程需等当前进程执行完 / 主动放弃 CPU;
- 抢占式:高优先级进程可打断当前进程(Linux 默认)。
- 时间片轮转(RR):普通进程默认用,时间片 5~10ms,宏观并行(用户感知同时运行),微观串行(CPU 单核同一时间仅执行一个进程)。就绪队列中的进程轮流占用 CPU,时间片到则切换到下一个进程,保证公平性。
- 多级队列反馈调度:结合优先级 + 时间片,不同优先级队列用不同时间片(高优先级时间片短),进程执行超时则降级到低优先级队列,兼顾公平与效率。
- 负载均衡调度:多 CPU / 多核场景,将进程调度到负载低的 CPU 核心,提升整体利用率。
1.6 进程的状态
运行态(R):任务正在被CPU执行
就绪态(R):任务正在处于就绪队列中,但未被CPU调度到
可唤醒等待态(S):任务等待某个资源被CPU挂起,等待过程中可以被唤醒
不可唤醒等待态(D):任务等待某个资源被CPU挂起,等待过程不能被打断;D 状态进程不能被 kill -9 终止,只能等其完成 IO 或重启系统
停止态(T):用户将某个任务暂停
僵尸态(Z):进程执行结束,空间未被回收;父进程未调用 wait/waitpid 回收资源;僵尸态(Z)只能通过杀死父进程解决
结束态(X):进程执行结束,空间也被回收
1.7、进程相关的函数接口
1.7.1 fork
- 函数原型
cpp
#include <unistd.h> // 头文件必须补充
pid_t fork(void);
- 功能 :创建一个新的子进程,子进程是父进程的 "副本";调用一次,返回两次(父 / 子进程各返回一次)。
- 参数:缺省
- 返回值 :
- 父进程:返回子进程的 PID(>0);
- 子进程:返回0;
- 失败:返回 -1(如系统进程数达到上限),并设置 errno。
- 内存拷贝机制:
子进程会拷贝父进程的文本段(代码)、数据段(静态变量、全局变量、字符串常量)、堆区(malloc)、栈区(局部变量)
- 执行逻辑 :fork 成功后,父子进程从 fork 的下一行代码开始并发执行(谁先执行由操作系统调度决定)。
- 示例代码:
cpp
#include <stdio.h>
#include <unistd.h>
int main() {
int a = 10;
pid_t pid = fork(); // 调用一次,返回两次
if (pid > 0) {
// 父进程执行区
a = 20;
printf("父进程:PID=%d,子进程PID=%d,a=%d\n", getpid(), pid, a);
} else if (pid == 0) {
// 子进程执行区
a = 30;
printf("子进程:PID=%d,父进程PID=%d,a=%d\n", getpid(), getppid(), a);
} else {
perror("fork失败"); // 打印错误原因
return -1;
}
return 0;
}
1.7.2 getpid
- 函数原型
cpp
#include <unistd.h>
pid_t getpid(void);
- 功能 :获取当前调用进程的 PID(进程唯一标识)。
- 参数:缺省
- 返回值:成功返回当前进程的 PID(始终 > 0);无失败场景。
- 使用场景:打印进程 ID、区分父子进程等。
1.7.3 getppid
- 函数原型
cpp
#include <unistd.h>
pid_t getppid(void);
- 功能 :获取当前调用进程的父进程的 PID。
- 参数:缺省
- 返回值:成功返回父进程 PID;无失败场景。
- 易错点:若父进程先于子进程退出,子进程会被 init 进程(PID=1)收养,此时子进程调用 getppid () 会返回 1。