📃博客主页: 小镇敲码人
💚代码仓库,欢迎访问
🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎
❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞
【深入浅出】Linux进程(三)
- 进程的优先级(普通进程)
- 进程优先级与权限问题
- 进程的调度与切换
- 相关概念介绍
- 环境变量
- main函数的参数
- 环境变量
进程的优先级(普通进程)
-
进程优先级的定义
内存中会同时存在多个
exe
文件,进而就会同时存在多个进程,这些进程可能会同时需要某个资源,比如CPU,他们需要依据进程优先级来排队,确定享受资源的先后顺序。进程优先级是操作系统的调度处理器时间给不同进程时所依据的一个数值或级别。这个值决定了进程在等待CPU时间片分配时的优先顺序和时间。优先级高的进程会比优先级低的进程更早获得CPU资源。 -
为什么需要进程优先级:因为资源是有限的!!!
-
Linux中如何设置进程优先级?
-
task_struct
结构体中有关于进程优先级的属性。- 用户通过设置
nice
值,来影响进程的优先级pri
。
- 用户通过设置
-
在
Ubuntu24.04
系统中,Linux中进程的默认优先级为20。我们通过设置进程的nice
值,来影响它的PRI
:-
PRI = PRI(old)+nice
值。这个PRI(old)
是默认的优先级20。 -
此时,我们允许进程
main
,它的默认PRI
为20,nice值为0: -
我们通过
renice
指令,可以用来调整正在运行的进程的nice
值,从而影响它的PRI
,renice [新的nice值] -p [进程pid]
,我们将nice
值设置为-10,按照计算公式,新的进程PRI = 20-10
应该为10:- 和我们预期的一致。
-
将
nice
值设置为10,新的进程PRI
应该为PRI = 20+10= 30:
-
-
Linux
中的nice
极值测试,nice
的范围[-20,19]:-
最小值(值越小,优先级越大):
- 这里其实显示的内容有点问题,应该是
old nice
为10,new nice
为-20,但是Linux
中nice
值和PRI
值是可以换算的,这样说也问题不大,就是容易误导初学者。
- 这里其实显示的内容有点问题,应该是
-
最大值(值越大,优先级越小):
-
-
Linux
还有一些特殊进程的优先级,不在[0,39]的范围内:- 这些
PRI
为负数的进程为实时进程,为正数的是普通进程,这样可以更好的区分它们。我们学习的主要是普通进程,大多数用户进程和后台服务都属于普通进程。实时进程暂时不做介绍。
- 这些
-
进程优先级与权限问题
-
普通用户是不能随意设置
nice
值。-
如果允许普通用户随意设置
nice
,它就可能会把属于自己的进程的优先级设置的很高,这样其它用户的进程就没办法享受到资源,就会造成饥饿问题。 -
但是普通用户可以把
nice
值增大(默认是0),降低自己的进程优先级(不能增加):-
介绍一个新的指令
nice
,它主要可以在进程启动时设置它的nice
值,nice -n [nice值]./可执行文件
:
-
-
如果降低
nice
值就会报错:
-
-
为什么
Linux
操作系统不允许直接设置PRI
值。nice
值相对较小,而且直观,用户友好性好。- 如果允许用户直接设置
PRI
值,可能会导致用户滥用高优先级进程,影响系统的整体性能和稳定性。通过nice
值,系统可以限制普通用户只能增加进程的nice
值(降低优先级),而不能减少nice
值(提高优先级)。
进程的调度与切换
相关概念介绍
-
进程在运行的时候,放在CPU上,执行指令,并不是必须一次性把进程代码跑完,现代操作系统都是基于时间片进行轮转运行的。
- 竞争性:系统中进程是有很多的,但是CPU只有一个,所以为了使用CPU,这些进程是竞争关系,也因此出现了优先级。
- 独立性:多进程运行,需要独享资源,运行期间互不干扰。
- 并行:多个进程在多个CPU下同时运行,这叫做并行。
- 并发:多个进程在一个CPU下以进程切换的方式,在一段时间内,让多个进程都能运行,看起来好像是同时运行,这叫做并发。
-
进程切换:现代操作系统中,多个进程按照时间片轮转运行,当一个进程的运行时间到了,它就会被挂起,为了让它下一次运行能接着运行,我们会保存这个进程的相关数据,这个数据就是上下文数据。所以,进程切换的本质也就是上下文数据的切换。上下文数据,也就是CPU中的寄存器信息。
- 寄存器和寄存器数据不是一个概念,每一个进程的寄存器数据都是私有的。
- 所有的上下文数据保存都是为了下一次的恢复,所有的恢复都是为了能继续上一次
pc
位置的运行。
-
进程调度:
-
进程调度算法:有很多不同的进程调度算法。
- 实时调度器(Real-Time Schedulers)
- SCHED_FIFO:实时优先级调度器,遵循 FIFO 原则。具有相同优先级的进程按到达顺序执行,高优先级进程总是优先于低优先级进程。
- SCHED_RR:实时轮转调度器,类似于 SCHED_FIFO,但每个进程有一个固定的时间片,时间片结束后进程会被移到队列末尾。
- 还有很多不同的调度策略,我们不再介绍,不管是怎么样的调度策略,一个优秀的调度算法,应该要考虑进程的优先级、进程的饥饿问题以及效率。
- 实时调度器(Real-Time Schedulers)
-
进程调度队列(
runqueue
运行队列):-
这个结构体中有两个关键的属性,就是活跃队列和过期队列。
-
活跃队列:活跃队列存储当前就绪且可以运行的进程。调度器会从活跃队列中选择下一个要运行的进程。
-
过期队列:过期队列存储已经用完其时间片但尚未完成的进程。
-
协调机制:当活跃队列为空时,调度器会将过期队列中的进程重新放入活跃队列中,以便继续调度。活跃队列和过期队列交换,变为空队列,初始时,所有的就绪队列都会放进活跃队列中。
-
活跃队列中存储的是进程描述符
task_struct
。 -
如何找到第一个非空活跃队列:通过位图,我们能快速筛选出非空队列,遍历一次就可以排除32个队列(如果
bitmap[i]
值为0),然后排除后,下次的队列下标就要加上32*i
(i
为排除了多少个32位)了,发现第一个不为32位的,最多遍历32次就可以找到如果bitmap[i] & (1 << j)
不为0,就说明该位置队列不为空,开始调度。这是设计bitmap
应该考虑的事情,这个数据结构会有相应的方法,判断某一位是否有值。
-
-
环境变量
在介绍Linux
的环境变量前,我们先来介绍一下main
函数的参数。
main函数的参数
是的,你没有看错,其实我们的
main
也有参数。
int main(void);
int main(int argc,char* argv[],char* env[])
这两种函数都可以用,argc
是命令行会自动传的,它会传命令行的参数的个数,以空格为分隔符,argv
存储我们的命令行参数,看下面的代码:
#include<stdio.h>
int main(int argc,char* argv[])
{
for(int i = 0;i < argc;++i)
{
printf("%d: %s\n",i,argv[i]);
}
return 0;
}
运行结果:
-
连续的空格会被视作一个分隔符。另外,我们的
main
函数只写两个参数是可行的,因为存在这种main
函数,实际上有三种main
函数。 -
传命令行参数给
main
有什么作用呢?我们可以通过不同的选项,让其执行同一程序的不同功能,这和我们的指令通过指定不同选项来实现不同功能的原理是一样的,所以命令行参数是Linux
指令的基础。看下面的demo
代码,使用命令行参数在同一程序中实现不同的选项执行不同的功能(加减乘):#include<stdio.h> #include <stdlib.h> #include<string.h> int main(int argc,char* argv[]) { if(argc != 4) { printf("Usage: \n\r%s: -[add | sub | mul] x y\n\n",argv[0]); return 1; } int x = atoi(argv[2]);//将字符串转为整数 int y = atoi(argv[3]); if(strcmp(argv[1],"-add") == 0) { printf("%d+%d=%d\n",x,y,x+y); } else if(strcmp(argv[1],"-sub") == 0) { printf("%d-%d=%d\n",x,y,x-y); } else if(strcmp(argv[1],"-mul") == 0) { printf("%d*%d=%d\n",x,y,x*y); } else { printf("Unknow!!!!\n"); } return 0; }
运行结果:
环境变量
- 环境变量:就是Linux系统内置的有特殊用途的变量,定义变量的本质是程序运行时在内存中开辟空间,然后把相应的内容写入这段空间中,操作系统/
bash
是用C语言写的程序,它也可以在运行中开辟空间,所以系统环境变量的本质就是系统给它开辟空间,给它变量的名字和内容。
-
查看系统中的环境变量的方法。
-
env
命令可以显示系统中的所有环境变量: -
echo $变量名
可以打印出某一个环境变量的值:
-
-
认识系统
Linux
中常见的环境变量:-
PATH
:指定命令搜索路径,当你执行一个命令系统会按照PATH
环境变量列出的路径去寻找这个命令,如果找到了就会执行它,没找到就会报错。 -
PWD
:存储当前所处目录的绝对路径,当你使用cd
命令切换 目录,PWD
变量会自动更新,pwd
命令不依赖于PWD
环境变量,而是通过系统调用函数getcwd
获取当前所处路径,就算你手动修改了PWD
变量的值,敲pwd
命令仍能正确显示当前所处路径。 -
USER
:存储当前的用户名。 -
HOME
:存储当前用户的主目录绝对路径。很多软件会根据这个环境变量,将配置文件放入主目录中,如.vimrc
、.bashrc
。这样做的目的有很多,比如可以做到个性化配置可以让不同的用户相互不干扰。 -
LANG
:指定了系统使用的语言,en_US
表示美国英语,zh_CN
表示简体中文。还指定了字符编码,常见的字符编码包括UTF-8
、ISO-8859-1
等。例如,en_US.UTF-8
表示使用 UTF-8 编码的美国英语。
-
-
环境变量具有全局属性,它能被系统中所有进程和子进程使用,C语言中
main
函数的参数env
就是来接受父进程bash
的环境变量的。#include<stdio.h> #include <stdlib.h> #include<string.h> int main(int argc,char* argv[],char* env[]) { for(int i = 0;env[i] != NULL;i++) { printf("%s\n",env[i]); } return 0; }
运行结果:
-
argv
和env
字符串数组最后一个值保存的NULL
:
-
-
修改系统中的环境变量:
-
在当前终端会话中临时设置一个环境变量,使用命令
export 变量名=值
: -
使用
unset 变量名
删除我们当前终端的环境变量,也是临时删除。 -
永久设置/删除,编辑配置文件
~/.bashrc
。
- 环境变量的来源多样,
~/.bashrc 文件只是其中之一
,它是一个用户级的配置文件,用户级的配置文件还有其它,除了用户级配置文件,系统级的配置文件/etc
目录中也有配置文件可以配置环境变量。
-
- 本人知识、能力有限,若有错漏,烦请指正,非常非常感谢!!!
- 转发或者引用需标明来源。