【Linux】进程优先级 | 进程的切换 | 环境变量详解
创始人
2024-05-26 05:49:20
0

  🤣 爆笑教程 👉 《看表情包学Linux》👈 猛戳订阅  🔥

💭 写在前面:我们先讲解进程的优先级,探讨为什么会存在优先级,以及如何查看系统进程、进程优先级的修改。然后讲解进程的切换,首次介绍进程的竞争性、独立性,以及并行和并发的概念,在通过讲解进程抢占引出可见寄存器与不可见寄存器。最后我们讲解环境变量,介绍环境变量 PATH,并且做一个 "让自己的可执行程序不带路径也能执行"的实践,讲解环境变量的到如何删除,最后再讲几个常见的环境变量。


Ⅰ. 进程优先级(Process Priority)

0x00 引入:什么是优先级?

我们先思考思考 权限 是什么?权限的本质是谈论 "能" 还是 "不能" 的问题。

那什么是 优先级 ?优先级是进程获取资源的先后顺序!

CPU 资源分配的先后顺序,就是指进程的优先权(priority)

优先权高的进程有优先执行权利。配置进程优先权对多任务环境的 Linux 很有用,可以改善系统性能,还可以把进程运行到指定的 CPU 上,这样一来就可以把不重要的进程安排到某个 CPU,可以大大改善系统整体性能。

0x02 为什么会存在优先级?

我们不妨先思考下我们日常生活中排队的本质,排队的本质可以说是 "确定优先级" ,

而插队行为就是更改优先级。因为排队造就了优先级,那我们为什么要排队?

​  可以不排队吗?可以,结果就是大家一窝蜂抢呗,全部用抢的。

"无理由暴力抢占式,优胜劣汰,我挤死你"

(前后时间来确认先后顺序) \rightarrow​ (谁能挤谁能撞谁就排到前面)

现实生活中一旦出现了抢,就难免会引发争执。

在比如说食堂买饭如果大家都不排队,如果你就是挤不过别人,就会一直买不到,

你就每次都要饿肚子,这在操作系统中叫做 "饥饿问题" 。

所以,排队主要是换了一种竞争方式,不以那么残酷的方式竞争,让进程都能 井然有序

我们之所以要排队,其实最主要的原因是因为资源不够!

如果资源是无限的,就像希尔伯特旅馆一样,该旅馆拥有无限多的房间,那也不需要排队的了。

200 名学生要去食堂吃饭,但窗口就 20 个,当然需要排队。如果窗口有 200 个,理论上不用排。

因为 系统里面永远都是进程占大多数,资源是少数。 这就导致了进程竞争资源是常态!

排队和进程资源竞争都是一定要确认先后的,它们的本质都是 确认优先级

本章我们要讲的是 Linux 的进程优先级,Linux 下的优先级有很多方式,包括设置和修改。

我们不建议修改优先级,如果你不懂调度器的调度算法,你随便修改优先级其实就是变相地 "插队" 了。你可以让你的进程尽快地得到了某种 CPU 资源或其它资源,凡是可能会打破调度器的平衡。其实你在用户层再怎么设置,也不会对调度器的调度策略产生什么影响。

再加上设置优先级没有什么意义,所以本章我们就不去讲解了。

0x03 查看系统进程:ps -l

🔍 查看系统进程:在 Linux 或者 Unix 系统中,输入  ps -l  命令则会输出内容:

$ ps -l    # 查看进程的优先级

我们写一个简单的 Hello 程序,令其每隔一秒发送一次 Hello:

#include 
#include int main(void) {while (1) {sleep(1);printf("Hello!\n");}
}

我们把它运行起来,此时我们使用  ps -l   查看:

因为  ps -l  只能显示当前终端下进程的相关信息,我们可以使用给它加上 \textrm{-a}​ 选项:

$ ps -la   

 

此时我们的进程 process 就显示出来了,我们重点关注 \textrm{PRI}​ 和 \textrm{NI}​ 列。

 Linux 中的进程优先级由两部分组成:\textrm{PRI\, +\, NI}

  • \textrm{PRI}​:优先级 (priority),默认进程优先级为 80​。
  • \textrm{NI}​:nice 值 (nice value) ,进程优先级的修正属性,取值区间为 [-20, 19]​ ,默认值为 0​ 。

📌 注意:数字越小,表示优先级越高;数字越大,优先级越低。(Linux 下)

优先级的部分我们在 task_struct 中也是可以找到的。
它的优先级和我们上一章讲的进程状态一样,也是个整数,在 task_struct 中表示:

0x04 进程优先级的修改

要更该进程的优先级,需要更改的是 \textrm{NI}​,而非 \textrm{PRI}​ 。

因为 nice 值是进程优先级的修正数据,所以一个进程不管是在启动前还是在运行中,想要修改优先级,都是通过修改它的 nice 值来达到目的。

其实,我们系统中是存在   nice  命令的,对应的还有   renice  。

$ nice  
$ renice

它们可以让我们在启动一个进程时直接指定优先级,或者启动中或启动前设置优先级。

感兴趣可以自行查阅,我们还是主要学习如何使用   top  命令去修改:

$ top

进入 top 后我们键入 \textrm{r}​ ,此时会发出询问:PID to renice [default pid=x]

在后面输入我们要修改的进程的 \textrm{pid}​ 即可,我们刚才进程的 \textrm{pid}​ 是 20332​:

然后会询问:PID to renice [default pid=1] 问你要设置哪个进程的 \textrm{pid}​:

这里居然提示  Failed  修改失败了!Permission denied (么得权限) !

​ 因为我们刚才说过:

"一个进程的优先级不能轻易被修改,因为会打破调度器的平衡"

如果你执意修改,你须具备 👑 超级用户 的权限 —— \textrm{root}​ !这里我们 sudo top 就行:

$ sudo top

 

 ​ 找到了找到了,我们继续,我们继续!

我们刚才将 nice 值修改为 -20,现在 \textrm{PRI}​ 优先级变成 60 了。

值得强调的是,Linux 不允许用户无节制地设置优先级,设置的优先级范围不能逾过下列区间:

\textrm{NICE}:\, [-20,19]

其取值范围是 -20​ 至 19​,一共 40 个可设置级别。

\textrm{PRI}​ 值越小越快被执行,Linux 的优先级是这样设置的:

prio = prio_old + nice;

所以,只需要改 nice 优先级就能变化。

📌 注意:每次设置优先级,这个 old 优先级都会被恢复成为 80 (跟上一次没关系)

Ⅱ. 进程的切换(Process Switch)

0x00 竞争与独立

竞争性:僧多粥少!系统进程数目众多,而 CPU 资源只有少量,甚至一个,所以进程之间是具有竞争属性的。为了高效的完成任务、更合理竞争相关资源,便具有了优先级。

独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。

进程运行具有独立性,不会因为一个进程挂掉或者异常而导致其它进程出现问题!

内核结构 + 代码和数据

❓ 思考:那么操作系统是如何做到进程具有独立性的呢?

(我们将在后续讲解进程地址空间时揭晓)

0x01 并行和并发

并行:多个进程在多个 CPU 下分割,同时进行运行,我们称之为并行。
并发:多个进程在单个 CPU 下采用进程切换的方式,在一段时间内,让多个进程都得以推进,称之为并发。

下面我们来理解一下并行与并发。

一般服务器都是双 CPU 的,所以双 CPU 的系统是存在的,就会存在多个进程同时在跑的情况。

如果存在多个 CPU 的情况,任何一个时刻,都有可能有两个进程在同时被运行 —— 并行 

但我们大家接触的、用的笔记本电脑基本都是单核的,单 CPU 的任何时刻只允许一个进程运行。

我的电脑是单 CPU 的,但是我的电脑中有各种进程都可以在跑啊?怎么肥事啊?

它是怎么做到的呢?

不要认为进程一旦占有 CPU,就会一直执行到结束,才会释放 CPU 资源。

所以一直让它跑,直到进程执行完,是不存在的,我们遇到的大部分操作系统都是 分时 的!

操作系统会给每一个进程,在一次调度周期中,赋予一个 时间片 的概念。

例:一秒钟之内每一个进程至少要被调度20次,每一次调度就是自己代码得以推进的时候。

在一个时间段内,多个进程都会通过 "切换交叉" 的方式,当多个进程的代码,在一段时间内都得到推进 ——  并发

0x02 进程抢占

❓ 思考:OS 就是简单的根据队列来进行前后调度的吗?有没有可能突然来了一个优先级更高的进程?

抢占式内核!我们现在的计算机基本都是支持 抢占 的。正在运行的低优先级进程,可能正在享受着它的时间片、推进着代码,但是如果来了优先级更高的进程,我们的调度器会直接把对应的进程从 CPU 上剥离,放上优先级更高的进程,这个操作就叫做 进程抢占

了解

a. 不允许不同优先级的进程存在的 
b. 相同优先级的进程,是可能存在多个的

task_struct* queue[5];

根据不同的优先级,将特定的进程放入不同的队列中!这其实就是一张简单的哈希表,后面列入的都是队列,其原理是通过哈希根据不同的哈希值确定队列的优先级,每一种优先级 Linux 都会维护一个队列。

举个最简单的例子,下面的 z 是如何得到已经释放的临时变量 a 的数据的?

int func() {int a = 10 + 20;return a;
}int z = func();

寄存器功不可没,拷贝一份到寄存器里去,然后再 \textrm{mov} 给 z 变量。

CPU 内的寄存器是:可以临时地存储数据

寄存器分为 可见寄存器 不可见寄存器

当进程在被执行的过程中,一定会存在大量的临时数据,会暂存在 CPU 内的寄存器中。

寄存器上数据的重要性:

我们把进程在运行中产生的各种寄存器数据,我们叫进程的硬件上下文数据。

  • 当进程被剥离:需要保存上下文数据
  • 当进程恢复时:需要将曾经保存的上下文数据恢复到寄存器中。

上下文在哪里保存?task_struct !

📌 注意事项:要准确区分,"寄存器" 和 "寄存器里的数据" 的区别。

  • 寄存器只有一套,但是寄存器里的数据有多份。

Ⅲ. 环境变量(Environment Var)

0x00 引入:思考一个问题

❓ 思考:为什么我们的代码运行要带路径,而系统的指令不用带路径?

如果我们直接输入我们的可执行程序,会显示 bash: process: command not found 

我们说过,执行系统的指令实际上也是程序,系统的指令你也是可以带上路径的:

其实,我们可以通过它的报错 "command not found" 发现些什么!

要执行一个可执行程序,前提是要先找到它。

现在我们的问题就可以转化成:为什么系统的命令能找到,而我们自己的程序找不到?

💡 真相

系统中是存在相关的 环境变量,保存了程序的搜索路径的!

为什么我们的代码运行要带路径,而系统的指令不用带?其本质是由环境变量 \textrm{PATH} 引起的!

0x01 环境变量 PATH 

我们可以通过 env 指令查看环境变量:

$ env

这些变量每一个都有它特殊的用途,系统中搜索可执行程序的环境变量叫做 \textrm{PATH}

我们可以通过 grep 去抓一下:

如何查看环境变量的内容?我们可以使用 echo  去显示:

$ echo $PATH

 在 \textrm{PATH} 前加上 $ 符即可打印出环境变量:

环境变量 \textrm{PATH} 中会承载多种路径,中间用冒号 ( : ) 作为分隔符。

我们再执行某一个程序时,比如执行 ls 时,我们的系统识别到 ls 的输入时,会在上面路径中逐个搜索,只要在特定的路径下找到了 ls,就会执行特定路径下的 ls 并停止搜索。

换言之,\textrm{PATH} 就提供了环境变量,可执行程序搜索的路径。

我们的 ls 在  usr/bin  路径下,这说明当前的 ls 在 \textrm{PATH} 中是可以被找到的,

所以执行 ls 的时侯自然可以不带路径,所以我们自己的  process 不带路径自然就不能执行。

因为当前的  process 所在的路径并没有这里的环境变量,程序在搜索的时侯找了路径也没有找到你这个可执行程序,搜索完找不到,自然就报 "command not found" 了。

0x02 实践:让自己的可执行程序不带路径也能执行

那我现在就想让我的可执行程序 process 不带路径直接执行起来,可以吗?

可以!我们先讲述一种简单粗暴的方式,直接把我们的可执行程序 cp 拷贝到系统的路径中:

$ sudo cp process /usr/bin/

既然系统的所有命令都在 usr/bin 路径下,那我们把我们的 process 拷进去就行了。

实际上,刚才那个操作我们可以称之为 "软件被安装到系统上",但是我们不建议你去自己安装。

也更不建议你将你的指令拷贝到 Linux 系统路径下,因为这会污染 Linux 下的命令池。

经常这么干时间久了你可能都忘了这个是干什么的,半年之后:

"诶!我这系统里怎么还有个 process?"

可能就分不清是你写的还是系统的了,所以我们不建议这么做!

更好的方式是将 process 所处的路径也添加到环境变量中。

前置:在 Linux 命令行中,我们也是可以定义变量的,命令行变量分为两种:

  • 普通变量
  • 环境变量(具备全局属性)

命令行上直接写,变量名等于值,你所定义的这个变量 a,就是 本地变量

(我们这里先对本地变量做一个小小的理解,稍后我们还会讲解的)

用系统查看环境变量的命令 env 去查看一下这个本地变量,会发现根本找不到,

因为它不以环境变量的形式存在,但是它是存在的!

如果你想让一个变量变成环境变量,你可以通过 export 导出一个在系统中可以查看的环境变量:

$ export []=[]

通过 env 并 grep 一下这个变量,我们就能找到我们导出的环境变量了:

(至于环境变量和本地变量之间的差别,我们稍后再讲)

现在我们知道该如何导环境变量了,现在我想执行我的程序不想再带路径该怎么办呢?

💭 操作演示:下面我们来做个好玩的:

把我们的环境变量,当前路径导入到 \textrm{PATH} 路径中看看会发生什么:

$ export PATH=[路径]

这么一导之后,我们发现我们的 process 可以跟系统指令一样不带路径直接执行了:

但是好像我们的系统指令全都寄了!!!

 啊这,怎么会这样呢?!

因为你把 \textrm{PATH} 里的环境变量都搞没了,只剩你自己的路径了,所以这些指令自然都找不到了。

出现了你刚才自己可执行程序不带路径后 Enter 的报错 "command not found" 。

 这……难道环境污染了(紧张)?我的要服务器坏掉了(害怕)?

不用担心!在命令行上设置的环境变量是具有临时性的,只在你登陆期间有效。

你刚才的修改只是在内存中的修改,不会修改系统当中的相关配置文件。

所以你只需要关掉重开就行了,随便搞,不会影响。

如果你想让你的环境变量设置永久有效的话,是需要更改配置文件的,该配置文件在系统当中,跟云服务器没有关系。

那我们该怎么做呢?来,这么做:

$ export PATH=$PATH:[路径]

0x03 环境变量的导入和解除

刚才我们通过 export 去导入变量,如果想取消一个变量,就可以使用 unset 来取消变量设置:

此时我们使用 unset 环境变量,就可以解除 foo:

" 这些东西实际上都是 shell 命令,export 是导出,unset 是取消 "

0x04 介绍几个常见的环境变量

刚才我们介绍了环境变量 \textrm{PATH},它是用来指定命令的搜索路径的。 

下面我们来详细介绍一下常见的环境变量,刚才我们就是用 env 指令去查看环境变量的:

我们能看到有很多环境变量,比如下面这个 \textrm{HOSTNAME} 就是表示 "对应这台主机的主机名" 。

我们同样也是可以通过 echo 指令带上 $ 去查看环境变量:

echo $HOSTNAME

再比如 \textrm{SHELL},它可以告诉你你的 shell 在哪里,通常是 /bin/bash 

echo $SHELL

得益于 Linux 存在历史命令的记录功能,我们可以在 Xshell 里 ↑ ↓ 显出历史命令,就像这样: 

"总不能一直记吧?肯定是有个指令记录的阈值的!"

没错!Linux 最多允许你记录的历史命令条数是 3000。

而我们接下来要介绍的 \textrm{HISTSIZE}  (History Size),就是定义一共记录多少历史指令的环境变量:

$ echo $HISTSIZE

顺便一提,我们可以通过 history 命令令去查看我们历史敲过的所有命令:

 再来!我们再说几个 ~

我们一般是通过 whoami 指令去查看当前是谁正在使用系统的,而 \textrm{USER} 就记录了当前谁在用。

$ echo $USER

 ​​​​​​

不知道大家有没有关注过,每次登陆服务器默认所处的路径?就是默认所处的工作目录。

root 用户的工作目录和普通用户的工作目录不同,那 Linux 是如何知道的呢? 

\textrm{HOME}:指定用户的主工作目录(即用户登陆到 Linux 系统中时,默认的目录)

当然还有很多,比如 \textrm{SSH-CLIENT} 记录了谁登的服务器、地址、端口号等。

(环境变量实在多,全部讲完不太现实,上面我们讲的都是一些常用的,欢迎补充)

0x05 尾记

命令行中启动的进程,父进程全部都是 bash 。

环境变量具有全局属性,环境变量是会被子进程继承下去的。

所谓的本地变量,本质就是在 bash 内部定义的变量,不会被子进程继承下去。

Linux 下大部分命令都是通过子进程的方式执行的,但是还有一部分命令不通过子进程的方式执行,而是由 bash 自己执行(调用自己的对应的函数来完成特定的功能,比如 cd 命令),我们把这种命令叫做 内建命令

📌 [ 笔者 ]   王亦优
📃 [ 更新 ]   2022.3.
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,本人也很想知道这些错误,恳望读者批评指正!

📜 参考资料 

C++reference[EB/OL]. []. http://www.cplusplus.com/reference/.

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

百度百科[EB/OL]. []. https://baike.baidu.com/.

比特科技. Linux[EB/OL]. 2021[2021.8.31 

相关内容

热门资讯

你的晚安是我的早安是什么歌曲 你的晚安是我的早安是什么歌曲苏天伦《你的早安是我的晚安》“你的晚安是我的早安”是单小源的歌曲《东京遇...
积极进取的小故事 积极进取的小故事现代的普通人,不要名人的。不能与别人重复,尽快回答   啄木鸟的故事       啄...
熊出没之探险日记3什么时候播出... 熊出没之探险日记3什么时候播出?熊出没之探险日记3,春节前播放。熊出没只是探险日记三2020年5月4...
谁知道所有有关“七”的歌?拜托... 谁知道所有有关“七”的歌?拜托了各位 谢谢就是歌曲名里有“七”这个字的!谢谢七月七迅谈日晴 看我七十...
求一本小说 女主穿越了三次 每... 求一本小说 女主穿越了三次 每次都在福临身边 后来怀孕了孩子被打掉了那个 女主叫什么雯?那个女主就是...
如果记忆不说话,流年也会开出花... 如果记忆不说话,流年也会开出花的基本信息书 名:《如果记忆不弯饥好说话,流年也会开出花》埋铅 作 者...
你好,旧时光漫画版在哪里可以看... 你好,旧时光漫画版在哪里可以看?暂时在绘心上连载
一首英文歌,男的组合唱的,MV... 一首英文歌,男的组合唱的,MV是一个婚礼的过程。求歌名。是不是darin的can'tstoplove...
为什么很多人喜欢用胶片相机? 为什么很多人喜欢用胶片相机?有一种情怀叫做“怀旧“吧,现在数码相机越来越普遍了,已经到了”全民摄影“...
女主先爱上男主,男主却不喜欢女... 女主先爱上男主,男主却不喜欢女主或者是另有所爱,最后女主男主还是在一起的穿越小说。有木有再生缘:我的...
爱情失恋伤感句子 爱情失恋伤感句子越是美好的从前,越幸福的曾经,现在只能带来锥心的疼痛,痛到撕心裂肺,肝肠寸断,终于痛...
24岁穿这个会不会显老 24岁穿这个会不会显老有点显老,这个颜色款式,颜色有点暗,没有活力,属于那种气质佳,长得高雅的女人,...
哈尔的移动城堡英语版 哈尔的移动城堡英语版可以发给我吗度盘~请查收~
秦时明月之万里长城什么时候播 秦时明月之万里长城什么时候播据说是今年暑假开播别急,官网什么的信他你就输了,12年之前底应该会出,杭...
孩子会得抽动症吗? 孩子会得抽动症吗?我天生的气性比较大,有时跟别人斗嘴时候就会手脚哆嗦,麻木,我问一下这是不是抽动症就...
亨德尔一生为音乐献出了怎样的贡... 亨德尔一生为音乐献出了怎样的贡献?亨德尔一生写了歌剧41部,清唱剧21部,以及大量的管乐器与弦乐器的...
礼仪起源和发展的经典故事? 礼仪起源和发展的经典故事?一、礼仪的起源;1、天神生礼仪;2、礼为天地人的统一体;3、礼产生于人的自...
描写桂林山水的句子有哪些? 描写桂林山水的句子有哪些?天下风光数桂林有杨万里的“梅花五岭八桂林,青罗带绕碧玉簪”;有邹应龙的“无...
避免与强敌正面对决的成语 避免与强敌正面对决的成语避免与强敌正面对决的成语避实就虚 【近义】避重就轻、避难就易、声东击西【反义...
多愁善感类的成语 多愁善感类的成语心细如发【解释】:极言小心谨慎,考虑周密。亦作“心细于发”。【出自】:吴梅《题天香石...