如何增加网站访问量,会展展厅设计,如何自己设计广告图,公众号关键词排名优化目录 Linux—进程学习—31.进程优先级1.1Linux中的进程优先级1.2修改进程优先级—top 2.进程的其他概念3.进程切换4.环境变量4.0环境变量的理解4.1环境变量的基本概念4.2添加环境变量—export4.3Linux中环境变量的由来4.4常见环境变量4.5和环境变量相关的命令4.6通过系统调用获… 目录 Linux—进程学习—31.进程优先级1.1Linux中的进程优先级1.2修改进程优先级—top 2.进程的其他概念3.进程切换4.环境变量4.0环境变量的理解4.1环境变量的基本概念4.2添加环境变量—export4.3Linux中环境变量的由来4.4常见环境变量4.5和环境变量相关的命令4.6通过系统调用获得环境变量4.6.1 getenv4.6.2 putenv 4.7本地变量总结 4.8main函数的参数4.8.1命令行参数4.8.1.1命令行参数的意义 4.8.2环境变量参数—char* env[]4.8.3总结 4.9环境变量的组织方式4.10获取环境变量的3种方式 Linux—进程学习—3
1.进程优先级
什么是进程优先级 CPU资源分配的先后顺序就是指进程的优先权priority。 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的Linux很有用可以改善系统性能。 还可以把进程运行到指定的CPU上这样一来把不重要的进程安排到某个CPU可以大大改善系统整体性能
要注意权限和优先级的区别 权限能还是不能 优先级都能先做还是后做。 为什么会有进程优先级 因为资源太少了需要资源的进程太多了。 就比如大多数计算机的cpu都只有一个而需要等待cpu的进程数量远远多于cpu这个资源的数量。 1.1Linux中的进程优先级
在Linux中优先级和进程状态一样其实就是2个整数。这个整数是放在PCB里面维护的属于是进程的一个属性
写一个小程序来查看进程优先级 输入ps -l和ps -al可以查看到一些重要信息【ps -al可以查看当自己运行的进程信息】 UID : 代表执行者的身份 PID : 代表这个进程的代号 PPID 代表这个进程是由哪个进程发展衍生而来的亦即父进程的代号 PRI 代表这个进程可被执行的优先级其值越小越早被执行 NI 代表这个进程的nice值【默认是0】
Linux比较特殊其最终优先级 PRI(刚被创建出来就被赋予的优先级) NI
PRI and NI PRI也还是比较好理解的即进程的优先级或者通俗点说就是程序被CPU执行的先后顺序此值越小进程的优先级别越高 NI就是我们所要说的nice值了其表示进程可被执行的优先级的修正数值 PRI值越小越快被执行那么加入nice值后将会使得PRI变为PRI(new)PRI(old)nice 这样当nice值为负值的时候那么该程序将会优先级值将变小即其优先级会变高则其越快被执行 调整进程优先级在Linux下就是调整进程nice值 nice其取值范围是-20至19一共40个级别 这说明Linux是支持进程在运行中调整进程优先级的【更改NI实现】
要注意 进程的nice值不是进程的优先级他们不是一个概念但是进程nice值会影响到进程的优先级变化 1.2修改进程优先级—top
修改进程优先级其实没有什么必要因为会不会修改另说很多时候修改完的效果并不会说有想象的那么好。除非是追求极致效率不然没有必要去修改进程优先级。
这里演示一个修改进程优先级的方法——使用top修改进程优先级
top修改优先级的方法 进入top后按“r”–输入进程PID–输入nice值 验证一下
进场优先级的修改可能会需要root权限因此调用top的时候可以使用sudo top 正常输入r弹出来的进程是一个默认进程如上图所示默认进程的ipd是9152、
这里的小程序仍然是上面那个。 输入要修改优先级的进程的pid然后就会对我们输入的pid的进程进行修改如下图所示 然后输入在对25849的进程优先级输入一个-100 退出top工具出来查看进程优先级发现NI和PRI都发生了变化【PRI最终是60变小了因此该进程的优先级变高了】 但是该进程退出后在重新运行的话优先级还是默认的 这里需要注意——Linux是不会让用户过度的修改NI值的。 这是因为如果用户将自己的进程的优先级调的非常高那么就会导致这个进程经常需要占用CPU这样就会导致操作系统的调度失衡其他进程很可能没办法占用到cpu资源了。因此Linux不会让用户过分的去调低NI值来让进程的优先级过高 NI的值前面也说了范围就是-20至19一共40个级别。
因此Linux中用户能够修改的最终的优先级范围就是[80 - 20, 80 19]。
2.进程的其他概念 **竞争性**系统进程数目众多而CPU资源只有少量甚至1个所以进程之间是具有竞争属性的。为了高效完成任务更合理竞争相关资源便具有了优先级 **独立性**多进程运行需要独享各种资源多进程运行期间互不干扰。哪怕其中一个进程挂了但是不会影响另外一个进程运行。
为了维持这个独立性需要耗费更多的资源来维护【学习进程地址空间之后才能理解】 **并行**多个进程在多个CPU下分别同时进行运行这称之为并行 并发 多个进程在一个CPU下采用进程切换的方式在一段时间之内让多个进程都得以推进称之为并发
对并发需要知道的
一个cpu在任意一个时刻下只能够运行一个进程也就是只能被一个进程占用。
在cpu资源只有一个或2个的情况下为了能够在一段时间内推进多个进程运行的现象叫做并发。
这是如何做到的呢其实主要靠的是一个策略——时间片 其实就是一个进程操作系统规定你只能占用cpu资源多少时间。时间到了就必须将cpu资源让出来让其他进程占用cpu。这里有个现象是进程切换。 3.进程切换
前面也说了CPU比较蠢需要分析并接受外部的指令和数据才能够进行运算。
因此CPU只干三件事情【1.取指令、2.分析指令、3.执行指令】
在这个前提下进程再被CPU执行的时候其实CPU就是不断的在重复这三步这个过程用到了很多的寄存器一个CPU内部会有一套寄存器。
对于进程切换的一些知识和理解先看下面这个图 对进程切换的分析 进程再被执行的时候肯定会产生非常多的临时数据这些临时数据在执行的时候都在寄存器当中运算。这些数据都是属于当前进程的也就是说当该进程的时间片到了之后其他进程占用CPU之后这些临时数据就会被清空。 但是会有一个情况当进程的时间片到了之后如果进程还没有执行完那么就要考虑该进程回到CPU的情况。 因此操作系统会将该进程退出时寄存器内的临时数据在另外一个地方备份起来【上下文保护】并记住这个进程然后清空寄存器内的临时数据来给下一个切换进来的进程使用。然后每次进程切换的时候都要判断新进来的进程是不是之前有记录的未执行完的进程如果有记录的话就将之前备份的临时数据拿出来继续执行该进程【上下文恢复】。从而实现上下文数据的恢复。 总结 进程在切换的时候要进行进程的上下文保护 进程恢复运行的时候要进行进程的上下文恢复
4.环境变量
4.0环境变量的理解
为了更好的理解环境变量这个概念下面先讲个帮助理解的例子
在Linux中我们输入系统的指令是直接输入的【比如ls man who等指令】、而我们自己写的可执行程序也可以理解成指令。
但是我们自己写的可执行程序却要加一个./ 我们查看文件类型会发现s和自己写的process都是可执行程序 那是为什么呢这是因为系统找得到系统指令池的指令找不到我们自己写的指令。
这也就是为什么我们要执行自己的指令需要加上./的原因这里的./是当前路径的意思告诉系统在当前路径找到process这个指令去执行。而系统的指令都放在了usr/bin下
如果我们想要自己的指令也可以像系统指令那样执行通过root权限将自己的指令移动到usr/bin这个目录下即可。【但是我们不推荐这样做因为自己写的程序是没有测试的不稳定也不安全会污染系统指令池】
但是为什么在usr/bin这个路径下系统就找得到而在自己这个路径下系统就找不到呢
这就跟要谈的环境变量有关系了系统中有一个环境变量叫做PATH这个环境变量是系统启动的时候定义的一个全局有效的环境变量 可以看到每个冒号中间间隔的都是一个路径那么在执行一个指令的时候操作系统就会在环境变量PATH提供的这些路径当中去找、找到了就执行
如果这些路径下都没找到该指令的时候就会报错—找不到该指令 要注意环境变量不是只有PATH环境变量是有很多的
4.1环境变量的基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。 环境变量通常具有某些特殊用途还有在系统当中通常具有全局特性
环境变量其实就是操作系统为了满足不同的应用场景而预先在系统内设置很多的全局变量。
而这些变量一直都会被其他进程所访问到。
4.2添加环境变量—export
添加环境变量有个需要注意的问题下面做个案例 可不敢想下图一样直接将要添加的路径直接添加到环境变量中 这样会导致环境变量只剩下你所添加的这个路径之前的路径都会被覆盖的。 但是如果真的覆盖了其实问题也不大因为环境变量这个东西只要关掉这个命令行客户端然后重新打开环境变量就会重置了。原因是啥后面才学。这里只需要知道即可 由于之前的环境变量被覆盖会导致原来系统的指令也用不了的。 正确的添加环境变量的方法 输入export PATH%PATH:要添加的路径 这样就可以在原来的环境变量上添加一个新的路径 这样就可以直接像执行系统指令一样直接执行自己的程序并且 which自己的指令也会直接出现指令所在的路径因为which能够在环境变量中找到
4.3Linux中环境变量的由来
在Linux中用户的根目录下存在两个隐藏文件如下图所示: 这两个文件的内容如下图所示 每次用户登录的时候系统都会执行一次这两个文件通过这两个文件来构建当前用户的shell环境变量。【这两个文件的内容看不懂很正常】
为什么用户修改环境变量每次登录的时候环境变量都会被重置的原因就在这这里。
用户每次登录系统都会登录上面所说的两个文件来加载环境变量。
4.4常见环境变量 PATH : 指定命令的搜索路径 HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录) SHELL : 当前Shell,它的值通常是/bin/bash。
除了这些环境变量还有很多环境变量比如为什么我们能找到之前所输入的指令就是因为Linux当中帮我们记住了我们所输入的一些指令记录。比如Linux内核怎么知道我们用的是那个类型的shell呢也是通过环境变量解决的。
环境变量其实就是操作系统为了满足不同的应用场景而预先在系统内设置很多的全局变量。
输入env指令可以查看系统所有的环境变量。 比如里面有一个环境变量叫做HISTSIZE这个环境变量的3000就是Linux系统能帮我们记住3000条历史指令记录 4.5和环境变量相关的命令 echo: 显示某个环境变量值 export: 设置一个新的环境变量 env: 显示所有环境变量 unset: 清除环境变量 set: 显示本地定义的shell变量和环境变量
4.6通过系统调用获得环境变量
下面将通过系统调用获得环境变量的实验来加深对环境变量的理解
4.6.1 getenv
除了通过env来显示环境变量我们也可以通过系统调用来获得环境变量。
下面做个小实验
我们通过getenv()这个接口来获得环境变量
getenv的官方介绍 因此我们来做个实验通过系统调用来拿到USER这个环境变量的值
实验的代码如下 Makefile文件的内容如下 执行程序的结果如下 可以看到getenv拿到了USER这个环境变量的值 因此如果USER环境变量改变了这里执行的结果也会进行改变
实验如下登录root用户然后再执行此文件
输入su -登录root用户此时发现USER环境变量已经加载成root了。 那此时在执行我们能写的程序结果会跟着改变吗
如下图所示 结果与预期相符。通过系统调用能够获得环境变量
既然系统调用能够获得环境变量这样就能够判断当前用户的身份了从而就可以判断当前用户是否有权限去访问某个文件了。
【这也就是为什么用普通用户身份无法访问一些文件因为系统通过拿到用户的USER环境变量来判断当前用户这个身份有没有权限访问该文件**if语句判断在拿到当前文件的属性是能够被谁访问的stat拿到文件属性从而判断当前用户没有权限访问该文件从而输出Permission denied**】 下面手动实现一下权限是否足够的判断 实验结果 还可以再讲一个加深理解环境变量的例子 ls指令不论什么时候都可以知道用户当前所处的目录凭什么为什么执行自己写的程序的时候需要./mycode而ls mycode不需要ls ./mycode? 这是因为ls每次都知道当前的路径自然也不需要用户手动添加相对路径给shell了。那ls凭什么知道用户所处的路径呢——凭环境变量PWD ls也是一个可执行程序是一个指令因此每次它执行都相当于bash的子进程都可以继承到全局属性的环境变量因此每次执行lsls都可以通过环境变量PWD来知道当前路径自然就不需要用户手动告诉shell相对路径了 而每次变更路径的时候bash都会及时的更新环境变量PWD而ls每次执行又可以继承到全局属性的环境变量因此不管用户在哪里ls都可以通过环境变量PWD来获取当前路径。 4.6.2 putenv
这个系统调用目前来说用不到。**功能就是添加或者修改一个环境变量。**后面学习完进程控制自己写一个简单的命令行解释器的时候会使用它 4.7本地变量
系统的环境变量可以说是一个全局有效的变量在Linux中除了这种全局变量还可以定义局部变量 可以看到通过echo是可以获得到该环境变量的但是这个并不是添加了一个系统的环境变量 如上图所示env展示的系统环境变量中并没有myval的存在
说明这个myval是一个shell创建的一个局部变量只在shell有效
但是如果非要查看到myval的存在可以用setset展示的变量巨多包括了环境变量和本地变量
下面做一个实验通过getenv来看看是否能够获取到变量myval
代码如下 执行程序的结果如下 想要myval变成系统的环境变量可以使用export来导入 但是这个导入的环境变量也只是临时的只需要重启shell就会消失。因为重启shell会重新根据环境变量的配置文件来导入环境变量
总结 环境变量是全局的代表它是可以被子进程继承的。因为mycode程序运行时对于bash来说就是一个子进程但是它仍然可以获取环境变量。 为什么子进程需要继承环境变量呢——因为可以满足不同的应用场景比如执行命令时候的身份认证PATH的指令路径 本地变量就无法被继承。它只对当前进程(bash)有效 4.8main函数的参数
4.8.1命令行参数
之前的学习中又见到过main函数是有3个形参的。这个参数叫做命令行参数
int main(int argc, char *argv[], char *envp[]);这里的这个argc是决定 argv这个指针数组有多少个元素的。而argv这个指针数组装的都是char*指针一般来说都是字符串
这里做个实验来看看argv这个指针数组内装的字符串都是什么
自动化构建工具Makefile文件的内容 用c99是因为代码中出现了for(int i 0)这个代码
代码如下 执行结果如下 可以看到只有1个元素下标为0的第一个元素是这个可执行文件的名字
如果将在执行的时候加n个选项那么argc就会是n1argv数组就会有n1个元素如下图所示 那这个是怎么实现的呢 其实就是我们输的指令其实是一个长字符串然后shell会将我们的指令以空格为分隔符将这个长字符串切割成一个个小字符串也就是一个个指令然后每个指令都是一个字符串类型然后让根据argc来开辟argv的空间然后让argv存储着一个个指令。 看下图可以更好的理解 4.8.1.1命令行参数的意义
可以通过输入分割出来的小字符串来实现不同功能的实现——即argc和argv的应用
下面是便于理解的例子 下面是实验结果 经过这个实验结果可以看到命令行参数存在的意义利用argc和argv两个命令行参数执行同一个程序但是可以通过不同的选项来实现不同的功能
这个非常常见ls指令就是如此 在window中也有一个程序可以通过不同选项二实现不同功能的场景如下图所示 4.8.2环境变量参数—char* env[] env这个环境变量参数也是指针数组类型装着的就是系统中env所展示的环境变量 他的结构和argv是一样的只是每个指针变量都指向一个环境变量 。 因此可以看出环境变量其实是被系统当做一行字符串的。 下面做个实验——通过环境变量参数来获取环境变量
代码如下 for循环这样写是因为env[i]的最后一个元素是NULL因此肯定会停止循环
实验结果 4.8.3总结
那学习了命令行参数和环境变量参数之后就知道实际上在main函数运行的时候系统是会向main函数这个子进程传两个表的一个表是命令行参数表一个表是环境变量表。
这也就是为什么之前说环境变量是能够继承给子进程的
因此实际上自己的程序在执行之前系统是会帮我们做非常多事情的。
4.9环境变量的组织方式
前面说了main函数运行的时候系统会向其传两个表而环境变量就是通过传环境变量表传给main函数的。但其实c语言还提供了一个变量来获得环境变量——environ 这个environ是一个二级指针指向的就是环境变量的表的开头 每个程序都会收到一张环境表环境表是一个字符指针数组每个指针指向一个以’\0’结尾的环境字符串
因此可以不通过环境变量参数env来获取环境变量也可以通过environ变量来获取环境变量。
代码如下 libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。
执行结果如下 4.10获取环境变量的3种方式
通过c语言提供的接口——系统调用来获取环境变量【getenv】通过命令行参数中的环境变量参数——char *env[]通过c语言提供的一个全局变量——char **environ 这三个获取方式更推荐getenv因为很多场景都不是要获取全部的环境变量而是按照需要的环境变量去获取。而getenv可以直接通过环境变量的名字来获取到想要的环境变量