目录
编辑
1.进程基本概念与基本操作
1.1 概念
1.2 描述进程-PCB
1.2.1PCB的基本概念
1.2.2 task_ struct
1.2.3 查看进程
2.进程状态
2.1 Linux内核源码展示
2.2 进程状态查看
编辑
2.3 Z(zombie)-僵⼫进程
2.4 僵尸进程的危害
2.5 孤儿进程
3.进程优先级
3.1 基本概念
3.2 查看进程
3.3 PRI andNI
3.4 PRI vs NI
3.5 查看进程优先级的命令
3.6 四个重要概念
4.进程切换
5.内核进程O(1)调度队列
5.1 ⼀个CPU拥有⼀个runqueue
5.2 优先级
5.3 活动队列
5.4 过期队列
5.5 active指针和expired指针
6.环境变量
6.1 基本概念
6.2 常见环境变量
6.3查看环境变量方法
6.4 和环境变量相关的命令
6.5 环境变量的组织方式
6.6 通过代码如何获取环境变量
6.7 环境变量通常是具有全局属性的
1.进程基本概念与基本操作
1.1 概念
课本概念:程序的一个执行实例,对应正在运行的程序等。
内核观点:作为分配系统资源(CPU时间、内存等)的实体。
1.2 描述进程-PCB
1.2.1PCB的基本概念
• 进程信息存储在进程控制块(Process Control Block,简称PCB)这一数据结构中,它本质上是一个包含进程所有属性的集合。
• 教材中将其称为PCB(Process Control Block),在Linux操作系统中,PCB的具体实现是task_struct结构体。
注意:task_struct是进程控制块(PCB)的一种实现形式
• Linux系统使用task_struct结构体来描述进程
• task_struct是Linux内核的关键数据结构,它被加载到内存中并保存进程的所有相关信息
1.2.2 task_ struct
进程信息分类
• 进程标识符(PID):系统内唯一标识进程的编号,用于进程区分和管理
• 运行状态:记录进程当前状态(运行/等待等)、退出状态码及终止信号
• 优先级:决定进程调度顺序的优先级数值
• 程序计数器(PC):存储下一条待执行指令的内存地址
• 内存指针:包含指向程序代码、进程数据以及共享内存区域的指针集合
• 上下文数据:保存进程运行时CPU寄存器的状态信息
• I/O状态:记录进程I/O请求、分配设备及打开文件列表
• 统计信息:累计CPU使用时间、时钟周期、时间配额等资源使用记录
1.2.3 查看进程
(1)进程信息可通过 /proc
系统目录查看。
(2)大多数进程信息也可以通过用户级工具(如top和ps)获取。
ps:
注意:
查看特定进程信息时,可将ps与grep命令结合使用。
2.进程状态
2.1 Linux内核源码展示
• 要理解正在运行的进程的概念,需要了解进程的不同状态。在Linux内核中,进程有时也被称为任务。
以下状态定义于内核源代码中:
• 运行状态(Running):该状态并不意味着进程一定正在执行,而是表示进程要么正在运行,要么处于运行队列中等待调度。
• 睡眠状态(Sleeping):表示进程正在等待某个事件完成(这种睡眠状态有时也称为可中断睡眠(Interruptible Sleep))。
• 磁盘休眠状态(Disk Sleep):也称为不可中断睡眠状态(Uninterruptible Sleep),处于该状态的进程通常正在等待I/O操作完成。
• 停止状态(Stopped):可以通过发送SIGSTOP信号使进程进入停止状态(T)。被暂停的进程可以通过发送SIGCONT信号恢复运行。
• 死亡状态(Dead):该状态仅表示进程已终止,不会在任务列表中显示。
2.2 进程状态查看
ps aux
/ps axj
命令- a:显示当前终端的所有进程,包括其他用户的进程
- x:显示没有控制终端的进程,例如后台运行的守护进程
- j:显示进程所属的进程组ID、会话ID、父进程ID,以及与作业控制相关的信息
- u:以用户为中心的格式显示进程信息,包括用户、CPU和内存使用情况等详细信息
2.3 Z(zombie)-僵⼫进程
- **僵尸状态(Zombies)**是进程的一种特殊状态
- 当子进程终止后,若其父进程未通过
wait()
系统调用读取子进程的退出状态码,则该子进程会转变为僵尸进程 - 僵尸进程会保留在进程表中并维持终止状态,持续等待父进程获取其退出状态信息
- 只要满足以下条件,子进程就会进入Z状态:
- 子进程已终止
- 父进程仍在运行
- 父进程未获取子进程的终止状态
2.4 僵尸进程的危害
• 进程退出状态必须被保留,因为它需要向关注它的进程(父进程)汇报任务执行情况。如果父进程迟迟不读取状态,子进程就会一直保持Z状态。
• 保存退出状态需要用数据记录,这属于进程的基本信息,因此存储在task_struct(PCB)中。这意味着只要Z状态持续存在,PCB就必须一直维护这些信息。
• 如果一个父进程创建大量子进程却不回收,确实会造成内存资源浪费。因为每个数据结构对象都会占用内存空间,就像C语言中定义的结构体变量需要分配内存一样。
• 这确实会导致内存泄漏问题。
2.5 孤儿进程
- 当父进程先退出时,子进程会变成"孤儿进程"
- 孤儿进程将由1号init进程接管
- 最终由init进程负责回收这些孤儿进程
3.进程优先级
3.1 基本概念
- CPU资源分配的顺序取决于进程优先级(priority)。优先级高的进程享有优先执行权。在多任务环境下,合理配置进程优先级可以有效提升Linux系统性能。
- 系统还支持将进程绑定到特定CPU运行。通过将非关键进程分配到指定CPU,可以显著优化整体系统性能。
3.2 查看进程
以下信息值得重点关注:
• UID:执行者身份标识
• PID:进程唯一标识符
• PPID:父进程标识符(即衍生该进程的上级进程)
• PRI:进程优先级(数值越小优先级越高)
• NI:进程的nice值
3.3 PRI andNI
• PRI(进程优先级)表示程序被CPU执行的先后顺序,数值越小优先级越高
• NI(nice值)是进程优先级的修正数值,用于调整PRI
• 调整后的优先级计算公式为:PRI(new) = PRI(old) + nice
• nice值为负数时,PRI会降低,从而提高进程优先级,使其更快被执行
• 在Linux系统中,调整进程优先级实际上就是修改nice值
• nice值的有效范围是-20到19,共40个优先级级别
在Linux操作系统当中,PRI(old)默认为80,即PRI = 80 + NI。
3.4 PRI vs NI
• 需要明确的是,进程的nice值并非进程优先级本身,二者属于不同概念。但nice值会影响进程优先级的调整。
• 简单来说,nice值是对进程优先级进行修正的参数。
3.5 查看进程优先级的命令
使用 top 命令调整已运行进程的 nice 值:
- 运行 top 命令
- 在 top 界面按下 r 键
- 输入目标进程的 PID
- 输入新的 nice 值
注意事项:
- 也可以使用 nice 和 renice 命令来调整优先级
- 相关系统调用函数
3.6 四个重要概念
• 竞争性:系统运行多个进程,但CPU资源有限(可能仅有一个),因此进程间存在资源竞争。为优化资源分配和任务执行效率,引入了优先级机制。
• 独立性:多进程运行时各自拥有独立资源,彼此互不干扰。
• 并行:当存在多个CPU时,多个进程可以同时在不同的CPU上运行,实现真正的并行处理。
• 并发:在单个CPU环境下,通过快速切换进程的方式,在特定时间段内让多个进程交替执行,实现并发效果。
4.进程切换
CPU上下文切换是指任务切换或CPU寄存器切换的过程。当多任务内核需要切换运行任务时,会先保存当前任务的运行状态(即CPU寄存器中的所有内容),将其存入该任务的堆栈中。随后,内核会从待运行任务的堆栈中恢复其状态至CPU寄存器,并开始执行该任务。这一完整的任务切换过程称为context switch。
5.内核进程O(1)调度队列
5.1 ⼀个CPU拥有⼀个runqueue
若存在多个CPU,需考虑进程数量的负载均衡问题。
5.2 优先级
• 普通优先级:100~139(对应nice值的常规优先级范围)
• 实时优先级:0~99(无需关注)
5.3 活动队列
• 所有未用完时间片的进程按优先级存入该队列
• nr_active:记录当前处于运行状态的进程总数
• queue[140]:每个元素代表一个进程队列,同优先级进程遵循FIFO调度规则,数组下标直接对应进程优先级
• 进程选择流程:
- 从下标0开始遍历queue[140]
- 首个非空队列即为最高优先级队列
- 取该队列首进程运行,完成调度
- 虽然遍历时间复杂度为O(1),但效率仍不理想
• bitmap[5]:通过5×32位比特位(共140位)标记队列空状态,显著提升非空队列查找效率
5.4 过期队列
• 过期队列与活动队列具有相同的结构
• 处于过期队列的进程均为时间片已耗尽的进程
• 一旦活动队列中的所有进程处理完毕,系统将重新计算过期队列中进程的时间片
5.5 active指针和expired指针
• active指针始终指向当前活动队列
• expired指针始终指向过期队列
• 随着进程时间片到期,活动队列中的进程逐渐减少,过期队列中的进程持续增加
• 这种状态无需担心,只需在适当时机交换active和expired指针的内容,就能立即获得一批新的活动进程
重点:
系统查找合适调度进程的时间复杂度为常量,进程数量的增加不会影响时间成本,这就是著名的O(1)进程调度算法!
6.环境变量
6.1 基本概念
• 环境变量(Environment Variables)是操作系统中用于配置运行环境的关键参数
• 以C/C++开发为例:编译链接时无需手动指定库文件路径仍能成功生成可执行程序,正是依靠环境变量指引编译器自动查找所需库文件
• 环境变量具有两大典型特征:
- 承载特定的系统功能
- 通常具备全局生效的特性
6.2 常见环境变量
• PATH: 定义系统查找命令的可执行文件路径
• HOME: 设置用户的主工作目录(即用户登录Linux系统时的默认目录)
• SHELL: 指定当前使用的Shell程序,通常为/bin/bash
6.3
查看环境变量方法
To check the value of an environment variable, use:
echo $NAME # Replace NAME with your environment variable
//NAME:你的环境变量名称
测试PATH
将我们的程序所在路径加⼊环境变量PATH当中, 对⽐测试 export PATH=$PATH:hello 程序所在路径
直接执行./hello
与执行hello
的区别
为什么某些命令可以直接执行而不需要指定路径,而我们的二进制程序需要带上路径才能运行?
答案:
系统通过PATH
环境变量来查找可执行程序。PATH包含一系列目录路径,当输入命令时,系统会按照以下顺序查找:
- 首先检查是否是内置命令(如cd、echo等shell内置命令)
- 如果不是内置命令,则按PATH变量中列出的目录顺序搜索
- 在找到的第一个匹配的可执行文件处停止
6.4 和环境变量相关的命令
echo
: 显示指定环境变量的值export
: 设置新的环境变量env
: 显示所有环境变量unset
: 删除指定的环境变量set
: 显示当前 shell 的所有本地变量和环境变量
6.5 环境变量的组织方式
每个程序都会收到⼀张环境表,环境表是⼀个字符指针数组,每个指针指向⼀个以’\0’结尾的环境 字符串
6.6 通过代码如何获取环境变量
•
# 命令行第三个参数
借助第三方变量 environ
进行获取
注意:
libc 中定义的全局变量 environ
指向环境变量表。该变量未被包含在任何头文件中,因此使用时需要显式声明为 extern
。
6.7 环境变量通常是具有全局属性的
环境变量通常具有全局性特征,可被子进程继承使用。
直接查看,发现没有结果,说明该环境变量根本不存在
- 执行
export MYENV="hello world"
设置环境变量 - 重新运行程序后生效,证明环境变量成功传递给了子进程
(说明:环境变量具有继承性,父进程设置的变量会自动传递给子进程)