Linux 系统进程优先级决定 CPU 资源分配顺序,通过 PRI 和 Nice 值调节,root 用户可提升优先级。环境变量如 PATH 控制命令搜索路径,HOME 标识用户主目录,USER 存储登录用户名。命令行参数 argc 和 argv 传递外部输入,环境变量可通过 export 继承给子进程。内建命令 echo 可直接访问本地变量。掌握这些机制有助于优化系统性能及调试程序。
黑客28 浏览
前言
在 Linux 系统中,进程和环境变量是操作系统的核心组成部分。进程优先级决定了资源分配的先后顺序,直接影响系统性能;而环境变量则提供了一种灵活的方式,用于传递系统配置信息以及控制程序的运行环境。本篇文章将深入探讨进程优先级的概念、调节方法及其原理,以及环境变量的定义、特性和实际应用,帮助读者更好地理解 Linux 系统的核心机制。
一、什么是进程优先级?
优先级的定义:
优先级决定了多个进程竞争 CPU 时,哪个进程优先获得 CPU 时间片。
区别于权限,权限决定能不能执行某个任务,而优先级决定谁先执行。
优先级的作用:
通过优先级机制,操作系统能够公平地分配 CPU 资源,防止某些进程长期得不到 CPU 的问题(即进程饥饿问题)。
例如:
高优先级进程(实时任务)可以更快地执行。
低优先级进程可能被推迟,但不会被饿死(通过调度算法保证)。
小结:
CPU 资源分配的先后顺序由优先级决定。
Linux 的调度器根据优先级动态调度进程,提高系统的整体性能。
二、Linux 系统中的优先级
2.1 查看进程优先级
示例代码:
#include<stdio.h>#include<unistd.h>intmain() {
while (1) {
printf("I am a process, PID:%d, PPID:%d\n", getpid(), getppid());
sleep(1);
}
return0;
}
运行步骤:
打开另一个终端,查看进程的优先级:
ps -al | head -1 ; ps -al | grep process
编译运行程序:
gcc process.c -o process
./process
输出字段解析:
:表示进程的执行者身份。
UID
PID:当前进程的 ID。
PPID:当前进程的父进程 ID。
PRI:进程的优先级值,值越小优先级越高。
NI:进程的 nice 值,调整优先级的修正值。
2.2 PRI 和 NI 的关系
PRI(Priority):
表示进程的实际优先级,值越小优先级越高。
Linux 调度器根据 PRI 值决定哪个进程优先执行。
NI(Nice 值):
是进程优先级的修正值,用户可以通过调整 nice 值来影响 PRI 值。
nice 值范围:
[-20, 19],共 40 个级别。
默认值是 0。
nice 值的影响:
负数:提高优先级(PRI 值减小)。
正数:降低优先级(PRI 值增大)。
PRI(old):系统默认优先级,起始值为 80。
nice 值:用户设置的调整值。
举例:
默认情况下(nice=0),PRI 值为 80。
如果 nice=-10,则:
PRI = 80 + (-10) = 70 (优先级提高)
关系公式:
PRI(new) = PRI(old) + nice
2.3 修改进程优先级
查看进程优先级(top 命令):
找到目标进程的 PID。
修改优先级:
在 top 中,按下 r 键。
输入目标进程的 PID。
输入新的 nice 值(范围:-20 至 19)。
命令行方式修改:
调整运行中的进程:
renice <nice 值> -p <PID>
示例:
renice -5 -p 12345
启动新进程并设置 nice 值:
nice -n <nice 值> ./process
示例:
nice -n -10 ./process
使用 top 实时监控系统进程:
top
注意:
只有 root 用户 可以设置负的 nice 值(提高优先级)。
普通用户只能降低优先级。
2.4 进程优先级的实现原理
进程控制块(PCB):
每个进程在内核中对应一个 task_struct 结构体(即进程控制块)。
task_struct 中包含进程的优先级、状态等信息。
优先级队列:
系统根据进程的 PRI 值将其加入对应的优先级队列。
修改优先级的本质:
当调整进程的 nice 值时,内核会将该进程从当前队列移出,并重新加入新的优先级队列。
2.5 进程的特性
竞争性:系统进程数目众多,而 CPU 资源只有少量,甚至 1 个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。
并行:多个进程在多个 CPU 下分别同时运行,这称之为并行。
并发:多个进程在一个 CPU 下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
并发情况下,操作系统会根据每个进程的时间片进行进程间的切换,只要当前正在被 CPU 调度的进程的时间片到了,无论有没有执行结束,都会被操作系统从 CPU 上拿下来,放到 waiting 数组中去排队,等待 CPU 的下一次调度,我们把这种过程叫做进程基于时间片轮转的调度算法。
两个问题:
1. 为什么函数返回值,会被外部拿到呢?
函数调用过程中,栈会保存必要的信息,包括返回地址、参数和局部变量等。
返回值通过寄存器或栈上的特定位置传递给调用者:
如果返回值是通过栈返回,调用者会在栈上预留一块区域,函数直接将返回值写入这块区域。
在调用完成后,调用者通过栈指针或其他方法从指定位置获取返回值。
2. 系统如何得知进程当前执行到哪一行代码了?
CPU 中的程序计数器寄存器 ( PC 或者 eip ) 保存着当前正在执行指令的地址。每次指令执行完毕,程序计数器会自动递增(或根据控制流指令,如 jmp、call、ret 等更新),以指向下一条需要执行的指令。
补充知识:寄存器
CPU 中的寄存器有很多种,例如:通用寄存器 eax、ebx、ecx、edx;和栈帧有关的寄存器 ebp、esp、eip;和状态有关的寄存器 status。
寄存器扮演什么角色?提高效率,进程的高频数据会放入寄存器中。
寄存器也有对数据保存的能力,计算机在运行时一些重要的数据一定要保存在 CPU 内部,即寄存器中,因为寄存器离 CPU 很近且存储效率高,所以 CPU 内的寄存器保存的是进程相关的数据,可以随时被 CPU 访问或者修改,这种和进程有关的数据也被叫做进程的上下文。
进程在 CPU 上离开时要将自己的上下文数据保存好,甚至带走,这样做的目的是为了未来'回来'的时候进行恢复。进程在被切换的时候有两步:1. 保存上下文,2. 恢复上下文。进程的上下文数据量并不大,一般可以直接保存到进程的 PCB 对象中,当 CPU 再次调度该进程的时候,将这些上下文数据再恢复到寄存器里面即可。
除了上面提到的两种通过代码获取环境变量的方法(命令行第三个参数、getenv 系统接口)外,还可以通过全局变量 environ 获取
libc 提供的全局变量 environ,指向环境变量表。
需要 extern 显式声明后使用:
#include<stdio.h>intmain(int argc, char* argv[]) {
externchar **environ;
int i = 0;
for (; environ[i]; i++) {
printf("%s\n", environ[i]);
}
return0;
}
结语
通过对进程优先级和环境变量的深入学习,我们可以发现,它们在 Linux 系统中扮演着不可或缺的角色。进程优先级确保了多任务系统中资源的公平竞争和高效利用,而环境变量为系统和用户程序的交互提供了灵活性和动态配置的能力。掌握它们不仅能帮助我们优化系统性能,还能提升在日常开发和运维中的效率。希望通过本篇文章,能够让您对 Linux 系统的运行机制有更深入的认识,助力您的学习与实践。