在上篇中,我们了解了进程的标识、状态和内存属性。下篇我们聚焦进程的运行调度、IO 资源、权限与家族关系,拆解进程在系统中运行时的进阶属性。
一、进程的 “运行优先级”:调度类属性
系统中往往同时存在几十个甚至上百个进程,CPU 资源有限,调度器需要根据进程的调度属性,决定哪个进程优先获得 CPU、能运行多久。
1. 核心调度属性:优先级与时间片
- 优先级:决定进程被调度的先后顺序,优先级越高,越容易抢到 CPU。优先级分为静态优先级(创建时设定,运行中不变)和动态优先级(运行中根据行为自动调整)。
- 时间片:进程一次能占用 CPU 的最长时间。时间片用完,进程就会被强制换下 CPU,回到就绪队列。
主流的多级反馈队列调度算法,就是把优先级和时间片结合起来:优先级越高的队列,时间片越短;进程运行时间越长,优先级会逐步降低,时间片也会变长。
<div align="center"> <img src="..." ref="ref_25_0" alt="多级反馈队列调度示意图"> <p>图1:多级反馈队列调度逻辑</p> </div>
2. Linux 中的调度属性
Linux 系统把进程分为普通进程和实时进程,对应不同的优先级体系:
- 普通进程:使用
nice值调整优先级,范围是 - 20 到 19,数值越小优先级越高。普通用户只能调大 nice 值(降低优先级),root 用户可以调整到 - 20。 - 实时进程:优先级范围 0-99,数值越大优先级越高,永远比普通进程优先调度。用于对响应速度要求极高的场景,比如音视频处理、工业控制。
举例理解: 执行nice -n 10 ./my_program,启动程序时把它的 nice 值设为 10,降低它的优先级,让它少占用 CPU。 用ps -l可以看到进程的NI列(nice 值)和PRI列(实际优先级)。
二、进程的 “资源清单”:IO 与文件属性
进程运行时会打开文件、连接网络、占用设备,这些 IO 资源都被记录在进程的属性中,核心管理单元是文件描述符(File Descriptor, FD)。
1. 文件描述符:IO 资源的 “索引”
Linux 中 “一切皆文件”,进程打开的普通文件、网络套接字、硬件设备,都用文件描述符来标识。每个进程都有自己的文件描述符表,记录了它打开的所有 IO 资源。
文件描述符的底层是三层结构:进程文件描述符表 → 系统打开文件表 → inode 节点表:
<div align="center"> <img src="..." ref="ref_36_0" alt="文件描述符三层关系图"> <p>图2:文件描述符、打开文件表与inode的对应关系</p> </div>
三层结构的作用:
- 进程文件描述符表:每个进程独有,记录当前进程打开的文件,文件描述符就是这个表的下标(从 0 开始的整数)。
- 系统打开文件表:全局唯一,记录文件的偏移量、打开模式(读写 / 只读)等信息。
- inode 表:全局唯一,记录文件的物理位置、大小、权限等元信息。
默认情况下,每个进程启动时会自动打开 3 个文件描述符:
- 0:标准输入(stdin),对应键盘
- 1:标准输出(stdout),对应终端屏幕
- 2:标准错误(stderr),对应终端屏幕
2. 举例:查看进程打开的文件
使用lsof -p [PID]命令,可以列出一个进程打开的所有文件和资源,包括普通文件、网络连接、动态库等。比如查看 PID 为 1234 的进程打开的文件:
bash
运行
lsof -p 1234输出中可以看到文件描述符编号、文件类型、文件路径等信息,直观展现进程占用的 IO 资源。
三、进程的 “家族与权限”:衍生与安全属性
进程不是孤立存在的,它们有父子继承关系,同时携带权限属性,决定了进程能访问哪些系统资源。
1. 家族属性:父子进程与进程树
所有进程都是通过fork系统调用创建的:父进程复制出一个子进程,子进程继承父进程的大部分属性。这样层层创建,最终形成一棵以 PID=1 的systemd为根的进程树。
<div align="center"> <img src="..." ref="ref_41_0" alt="Linux进程树示意图"> <p>图3:典型Linux系统的进程树结构</p> </div>
除了父子关系,进程还有两个更高层级的组织:
- 进程组(Process Group):多个相关进程组成一个组,比如一个 shell 启动的多个管道命令属于同一个进程组,可以统一发送信号。
- 会话(Session):多个进程组组成一个会话,通常对应一个终端登录。关闭终端时,会话内的所有进程都会收到退出信号。
举例理解: 执行pstree命令,可以直观看到系统的进程树结构,清晰展示父子进程的层级关系。
2. 权限属性:UID 与 EUID
进程的权限由用户 ID(UID)决定,但为了灵活控制权限,Linux 还设计了有效用户 ID(EUID):
- 真实 UID(RUID):进程的实际所属用户,创建时继承自父进程,一般不会改变。
- 有效 UID(EUID):系统判断权限时实际参考的 UID,可以临时切换。
最典型的例子是passwd命令:修改密码需要写入/etc/shadow文件(只有 root 能写),但普通用户也能执行。因为passwd程序设置了 setuid 位,普通用户运行它时,进程的 EUID 会临时变成 root,获得写文件的权限,执行完后再恢复。
补充:安全属性现代操作系统还会给进程附加更多安全属性,比如 Linux 的 SELinux 安全上下文、容器的 cgroup 资源限制、沙箱权限等,进一步限制进程的行为,提升系统安全性。