进程(3)——进程优先级与环境变量【Linux】
一. 进程如何在cpu中如何执行
之前我们提到了什么是进程,还有进程的状态。
我们知道了进程的数据存储在内存中,但是我们还不知道CPU是如何执行进程的。
有些人就知道了,cpu执行进程,不就是读取代码吗,确实是这样。
所以我们这里要讲的是一些关于cpu与进程的一些细节。
1.1进程在CPU中的特性
进程在CPU中运行时有以下性质:
竞争性:系统进程数目众多,而CPU的资源只有少量,所以进程之间是要进行竞争的,这就有了下面要讲的优先级
独立性:多进程运行时,互不干扰
并行:多个进程在CPU下分别同时运行叫做并行
并发:通俗点讲,就是cpu采用进程切换
的方式来使多个进程同时推进
因为进程切换的速度实在是太快了,测试进程切换的速度都是要用仪器专门去测试的。
所以用进程切换的方式来达成实现给人感觉多个进程多个进行的感觉也是很容易的
而进程切换如此快就不得不提到寄存器了。
1.2 寄存器
寄存器可以说是一个在CPU中的非常小的高速存储器
还记得以前以前在函数栈帧中的一个现象。
为什么函数返回值会被外部拿到
我们用return,来返回值,return后,函数销毁,将返回值返回给调用函数的上级函数。
return a->mov eax10 会放到cpu的寄存器内
至于存在哪个寄存器取决于编译器
这里补充下:
返回对象时,会调用对象的赋值重载或者构造函数
而不是将整个对象返进行返回,因为当对象太大,而寄存器太小
所以这里回忆了一下寄存器后,我们通俗的讲寄存器的作用是:
寄存器是将对应的进程高频数据放入寄存器中,提高效率。
1.2.1 进程的上下文
而寄存器中存储的进程的高频临时数据,被称为进程的上下文。
当进程运行时:
寄存器中保存了许多进程的上下文。
当进程要进行切换时:
进程在从cpu上离开的时候,要将上下文数据保存好带走
而保存的目的都是为了未来恢复
所以在进程被切换的时候,寄存器要进行两个步骤:
1.保存当前进程的上下文
2.回复之前进程上下文
所以能实现进程的快速切换,寄存器可以说是功不可没
二. 进程优先级
这里我们上面提到过:CPU资源有限,进程是多个,所以进程之间是竞争关系。
而如果一个进程长时间得不到cpu资源
该进程的代码长时间无法得到推进的问题就是:进程的饥饿问题
2.1 如何查看进程优先级
我们要了解进程的优先级,首先要会查看进程的优先级
用这个指令就可以查看带有优先级的属性
ps -al
这里的PRI就是priority
进程的优先级
这里随便用一个一直持续的代码进行查看一下
这里我们来查看一下这个进程的优先级
ps -al | head -1 && ps -al | grep 5623
这里我们能发现他的PRI是80
2.2 修改进程的优先级
这里我们知道了如何查看进程的优先级后
我们应该知道如何修改进程的优先级
提到修改进程的优先级,就不得不提NI值(nice)
2.2.1 NI值
在上面这个优先级的图中,我们能发现PRI旁边就有NI值
为啥修改进程的优先级需要提到NI值
因为进程的优先度的修改是:
pri(new)=pri(old)+ni(nice)
所以可以说:
ni值是用来专门改变优先度值
而系统为了防止用户乱调,所以ni有限度【-20,19】
所以一个优先级是80的进程:调整范围是【60~99】
2.2.2 修改方法
改变进程优先级:
1.输入top
2.按下小写r
3.输入进程pid
4.输入想要改变到的优先度值
这里我们再查看一下PRI
这里我们能发现PRI变成了99
正好符合我们上面的通过NI的范围,得到的优先级范围。
三. 环境变量
我们在windows系统中,也见过很多环境变量
配置java或各类语言的环境变量中,也需要配置环境变量
但什么是环境变量:
3.1 什么是环境变量:
环境变量是一般是指:在操作系统中为了指定操作系统运行的一些参数。
环境变量提供的一组name=value形式的变量
不同的用户有不同的环境变量(这个是指不同用户的有的环境变量的值不同)
通常具有全局属性
这是因为:
我们运行的进程都是子进程,bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息
(所以环境变量信息通常是全局的,子进程会继承父进程的环境变量)
但是子进程改变环境变量的时候不会改变父进程的环境变量
3.2 PATH环境变量(随便挑个来认识)
3.2.1 功能认识
比如在Linux中,我们输入指令,操作系统可以直接执行指令
这个时候就用到了我们的PATH环境变量:
PATH环境变量就是:Linux中的指令搜索路径
我们讲过指令的本质就是文件。
但是操作系统可以找到我们输入的指令的对应文件。
这里我们能用which搜索pwd位置。
然后我们打印一下PATH环境
能发现PATH中有pwd所在的路径:
/usr/bin
3.3 环境变量的操作:
想到环境变量的操作无非就三个:
添加和查看还有删除
3.3.1 查看环境变量
这里的查看环境变量也有两种方法:
i. 命令行查看环境变量
查看所有环境变量的:
env
直接在命令行输入即可
这里能看到弹出了所有的环境变量。
查看指定环境变量:
echo $环境名
ii. 程序中得到环境变量
我们知道操作系统内核使用C语言写的
所以C语言也肯定有显示环境变量的接口:
C语言中包含头文件stdlib.h
getenv()函数
这里用getenc接口,直接查找到了PATH环境变量的
3.3.2 添加环境变量
知道如何查看环境变量后,紧接着就是添加环境变量了
这里添加环境变量也有两种方式:
i. 添加全新环境变量
添加全新的环境变量,就是自己命名自己定义自己添加的环境变量
export 变量名=对应值
这里我们进行添加了一个TEST进行测试
这里我们再用env进行查看,能看到环境变量被添加上去了。
ii. 在老环境变量上进行添加
覆盖:
平常的环境变量都是NAME=NUM
一般环境变量直接等于一个值的,要修改的话一般都是直接覆盖。
直接
变量名=值
直接修改即可
添加:
我们之前在上面见过,PATH环境变量存储着的是大量的指令搜索路径:
所以相比于进行覆盖,更需要的是在原路径的基础上进行添加新路径
PATH=$PATH:/自己文件路径
这里的$PATH代表的意思就是原PATH的路径
这里能发现path中新添加了我们的文件路径
但这里我们要注意,我们添加的所有的环境变量都是内存级的环境变量。
我们把shell重新启动后,环境变量就会消失。
3.3.2 删除环境变量
这里我们先随便添加一个环境变量
unset 变量名
即可删除变量
四.命令行参数
平常在一些书中可能会见过main函数可以传这种形式的参数:
int main(int argc,char* argv[])
{}
我们平常在编译器中写代码可能并不能见到。
但是我们开始在Linux中用命令行进行编写时,就可以好好来了解一下了。
这里我们先随便使用一下:
argv是一个指针数组其中存储了各个字符串。
那让我们遍历一下,打印argv中各个元素,进行查看。
发现这里argv存储的是命令行参数的分段。
这里就能来解释一下这个命令行参数的形式了
在我们平常在命令行输入参数时
./parm_test -a -b -c
在编译器眼中,你就是输入了一大段字符串:
"./parm_test -a -b -c"
之后编译器会将参数进行分组(存进argv中):
argv是指针数组,将各个字符串进行存储。
这里我们能看到后面的元素是空
所以我们遍历的方式还可以优化一下:
for(;argv[i];i++)
因为遇到NULL的时候,就相当于整数0,自动会停止。
4.1 main函数的env参数
这里如图里面说的 argv,env 都叫做核心向量表。
我们平常在一些教材里面,可能前两个比较常见,但是第三个确实是比较少见。
我们能看到这个env不就是我们前面的环境变量吗
但是这个env是指针数组的属性。
所以这里能看出,其实环境变量也是大段的字符串
所以之前env看到的环境变量实际上都是字符串
五. 本地变量
上面提了环境变量
这里就提一下本地变量
上面我们提过
环境变量有一个非常重要的特征:全局性
因为子进程会对父进程进行继承。
但是这里我们要提的本地变量则是不会进行继承的效果。
5.2添加本地变量
这里直接添加一个本地变量看看:
变量名=变量值
这个和环境变量的区别就是多加了一个export
这里我们添加上了一个变量
5.1 查看本地变量
添加上后,就要了解如何进行查看
当然不可能用env
进行查看。
因为env是用来查看环境变量
环境变量需要被子进程继承的,而本地变量不被继承
所以不会放在环境变量中。
这里要查看环境变量就要用
set
这里能看到这个set不光有本地变量还有环境变量。
这里我们用grep进行查找我们添加的环境变量。
5.3取消本地变量
这里我们找到添加的本地变量后。
就可以进行取消环境变量了
unset 变量名
这个还是和环境变量一样的删除方法
这里能发现删除成功了
六. bash中的两种命令:
这里为什么突然扯出bash行的命令:
因为:
这里我们直接能用echo来打印出本地变量。
我们之前明明提过,本地变量无法被子进程继承。
按道理来说,echo是一个指令,指令本质就是文件,而文件运行就是一个进程,bash创建进程运行时,需要创建echo的这个子进程。
所以按道理echo无法使用bash父进程的这个本地变量。
这里就要纠正一个误区了:
命令行启动的指令不一定要创建子进程。
这里就要将命令分成两类了。
6.1 常规命令
一种是:有些命令操作系统无法直接执行,需要调用文件,所以需要创建子进程
将功能交给子进程自己去执行。
这就叫做:常规命令——通过创建子进程完成的。
6.2 内建命令
还有一种是:系统执行起来特别有把握,可以说是拿手老活
这种就叫:内建命令——bash不创建子进程,而是自己亲自执行类似bash调用自己的写的,或者系统提供的函数