我想在这先完成上一章的一个未说完的话题.最后一个我们讲到了僵尸进程,是指子进程已经结束,但是父进程还在运行没有来得及回收.此时这个子进程便是僵尸进程.
但是如果父进程运行完了,也没有回收就直接结束了,那这个子进程改由谁维护呢?
此时孤儿进程会被1号init进程领养,当然要由init进程回收。
这个尾巴说完了,我们开始进入正题:
目录
进程的优先级
基本概念
查看进程优先级
PRI 和 NI
如何调整进程的优先级
PRI和NI区别
其它概念
竞争性
独立性
并行
并发
上下文
环境变量
概念
问题引入
常见环境变量
PATH
查看环境变量方法
导入PATH环境变量
HOME
SHELL
和环境变量相关的命令
环境变量的组织方式
获取环境变量
通过代码获取环境变量
通过系统调用获取或设置环境变量
环境变量通常具有全局属性
命令行参数
进程的优先级
基本概念
1.CPU分配资源的的先后顺序,就是指进程的优先权。
2.优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能.
3.还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
一句话:进程优先级是确认谁先得到资源,谁后得到资源.
那么为什么要有优先级呢?
本质是因为CPU有限,而进程太多.
进程太多,需要通过某种方式竞争资源.用例子来说:我们排队买票,军人可以享有优先权,普通人排队,这里军人的优先级就是比较高的.
在计算机中,我们可以用一些数据来表明优先级,只有优先级还不够,还得有评判,例如你在你们学校第一名,把你们放到孤岛上也没人在意你是年级第几,只有在学校,老师,领导才会根据这些成绩评判你,这样才有效.
这些评判优先级大小的叫做调度器.这个优先级便是我们的调度指标.优先级高的会先被调度到CPU执行.
查看进程优先级
先说结论:Linux下优先级具体的做法是:
优先级 = 老的优先级 + nice值.后面会说明这个.
我们先写一段程序.
然后老操作,一边执行,一边监视
发现我们进程也会有两个属性,ps -al是显示更详细的进程信息.
其中PRI代表这个进程可被执行的优先级,其值越小越早被执行.
NI代表nice值.
我们将分别介绍一下它们.
PRI 和 NI
关于PRI和NI,我们需要知道下面几个点.
1.PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,PRI值越小进程的优先级别越高.
2.NI就是我们所说的nice值了,其表示进程可被执行的优先级的修正数值.
3.PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice.
4.这样,当nice值为负值的时候,那么该进程将会优先级值将变小,即其优先级会变高,则其越快被执行
5.所以,调整进程优先级,在Linux下,就是调整进程nice值
6.nice其取值范围是-20至19,一共40个级别
如何调整进程的优先级
上面也说了,调整进程的优先级就是调整nice值.如何调整呢?
首先输入top指令,然后再按下‘r键.
会出现这么一句话,提示你输入要修改nice值的进程.
我们刚才运行进程的pid是23494,因此我们输入23494.
之后让我们输入nice值,我们输入15,此时的进程优先级应为之前的80+15=95.
我们再来看一下:
发现进程优先级确实如我们所想的,成为了95,NI值此时是我们调整的值15.
需要注意的是,每次调整都是以80为基准值开始调整,而不会受当前PRI值影响.
我们此时输入-15
它不会95-15而变成80,而是从80开始,80-15=65.
这结果正如我们所说的.
PRI和NI区别
PRI是进程的优先级,NI(nice)值是进程优先级的修正数据
进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
其它概念
竞争性
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级.
独立性
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰.比如浏览器挂了不会影响qq的正常使用.子进程挂了不会影响父进程,父进程挂了不会影响子进程.
并行
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行.
并发
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发.
这里大家有没有这样一个疑惑:并发采用进程切换的方式,那如果这个进程没有执行完,你切换到别的进程了,那么下次再切回来这个进程的时候,它从哪开始呢?从头开始?那效率太低了吧,我们想的应该是从原来的位置开始,那么CPU是怎么知道上一次执行到哪了呢?
上下文
这里先说一个现象:如果进程A正在被运行,那么CPU的寄存器里面,一定保存的是进程A的临时数据!这些临时数据,称为A的上下文,包括函数最后一次返回值是什么,运行状态,运行位置等等.
所以当进程A暂时被切换下来的时候,需要进程A顺便带走自己的上下文数据,相当于保存到进程A中.
暂时保存的目的:一定是为了下次再拿出来,能恢复上去,就能按照之前的逻辑继续向后运行,就如同没有被中断过一样.
CPU内的寄存器只有一份,但是上下文有多份,分别对应不同的进程!每次寄存器只能读取一份上下文.
环境变量
概念
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数.
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性.
问题引入
大家有没有注意过这样的现象:
我们运行的自己写可执行程序需要加上./(即当前路径),而像ls,touch,rm这些命令执行的时候不需要加./ ,当然如果加上它的路径也可以.
ls这些命令和我们写的唯一的不同点是:一个是我们自己写的,一个系统自带的命令,由于系统已经配置好了环境变量,所以才可以不用加路径直接运行.
现在知道这是环境变量的作用即可,后面讲完就会明白.
常见环境变量
PATH
查看环境变量方法
echo $PATH
注意它们之间的路径是以:为分隔符.
当我们输入ls的时候,系统会先从第一个路径查找,如果有就直接执行,如果没有,继续向后查找,直至找到,如果找完了都没有,那么就会报错,command not found,命令没有找到.
所以想要我们的命令执行也可以不用加路径,我们可以把我们写的可执行程序写到这些PATH路径中,但是我们不建议这样做,因为会污染别人已经写好的命令池.
所以我们可以把我们写的放到环境变量中,相当于是单独一个.
导入PATH环境变量
输入指令:
export PATH=$PATH:/home/liqi/process
里面这个:后面的是你可执行文件的路径,可以使用pwd查看
然后我们再次查看环境变量.
发现已经成功导入了.
我们此时便可以直接运行process下的可执行程序了.
当你退出登录重新进入的时候,环境变量又会初始化到最初的状态.
HOME
会记录显示当前用户的家目录.
所以之前说的cd ~,进入自己的家目录,实则是根据这个HOME进行的.
SHELL
显示当前的shell,通常是/bin/bash.
和环境变量相关的命令
1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的shell变量和环境变量
环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
获取环境变量
通过代码获取环境变量
实际上,我们main函数有三个参数,int argc, char* argv[],这两个是命令行参数,稍后会讲.
char* env[]是环境变量参数.
这个是一个指针数组,就是我们上一部分的那张表.
我们可以写下面一段程序:
然后退出,make编译,然后运行
可以发现,这样就把所有的环境变量输出出来了.
通过系统调用获取或设置环境变量
有两个接口:
putenv,是用来设置,后面会讲
getenv,获取环境变量.
例如我们想获得PATH环境变量.
输入代码:
然后make编译运行:
把PATH换成HOME:
同样地,也输出了出来.
我们有没有这么一个问题,是谁把这些环境变量导入到这些变量里呢?
其实是继承了父进程的环境变量,默认所有的环境变量都会被子进程继承。父进程正是我们的bash,这是一个简单的进程替换,后面会讲解.
这也另外说明了一个事实:环境变量具有全局属性!
因为它可以被很多子进程拿到访问到.
环境变量通常具有全局属性
我们做个实验来证明它:
我们把环境变量名改成了myenv.
可以发现什么都没有还出现了段错误.
此时我们再导入一个名为myenv的环境变量 .
export myenv="hello,world"
此时bash已经有了myenv这个环境变量.而运行一个程序需要先创建一个子进程,子进程也会继承父进程.正是由于环境变量具有全局属性!
此时我们再次make编译运行,便发现已经成功输出了这个环境变量.
这说明了两件事情:
1.子进程的环境变量是从父进程来的.
2.默认所有的环境变量都会被子进程继承(环境变量具有全局属性).
那么子进程的子进程也会继承子进程的环境变量
命令行参数
这个作为一个附加内容.
刚才我们讲解环境变量的时候说了,main()函数有三个参数,最后一个参数我们说了,那么还有前两个参数,这两个参数便叫做命令行参数.
我们写程序看看这是个什么东西.
我们发现,它其实是把我们输入的选项作为参数传入到了argv中,具体有多少,是由argc决定的.
这些命令行参数这有什么意义呢?
最大的功能是:让同一个程序,通过不同的选项,使用不同的子功能!
例如ls -a,ls -a 或者ls -a -l都是如此.
这些内部都是命令行参数完成的.
或者我们自己实现一个简易的
会是如下的场景:
所以这便是命令行参数的真正用法.