淘宝网商务网站建设目的,银行服务外包公司排名,深圳防疫隔离政策,库尔勒网站商城建设引言#xff1a;
北京时间#xff1a;2023/2/20/22:15#xff0c;昨天晚上#xff0c;看了一晚上的cs#xff1a;go#xff0c;主要原因是因为我的好舍友#xff0c;叫我开箱子#xff0c;然后就不可言语#xff0c;看了一晚上的开箱子和精彩剪辑#xff0c;不过这个…引言
北京时间2023/2/20/22:15昨天晚上看了一晚上的csgo主要原因是因为我的好舍友叫我开箱子然后就不可言语看了一晚上的开箱子和精彩剪辑不过这个游戏确实是颠覆了我对游戏的认知游戏里的装备居然是可以卖钱的我发现这个游戏机制非常好但是这个游戏对新手不太友好不然这个游戏还是挺快乐的并且该游戏里的装备也颠覆了我对钱的认知……今天就让我们来学习一下孤儿进程、环境变量、优先级和地址空间相关的知识。
什么是孤儿进程
在上一篇博客中我们已经学习了什么是僵尸进程我相信大家都知道我们是通过把某一个子进程使用kill -9 PID 的方式来把该进程给杀掉之后才导致一个进程从运行状态R或者睡眠状态S变成了僵尸状态Z所以可以想象如果此时我们不是把某个子进程杀掉而是把某个子进程的父进程杀掉此时是什么情况呢如下图 从上图的代码中我们可以看出我们使用fork()函数创建了两个一样的进程此时这两个进程可以同时执行while循环语句并且判断条件互不干扰重点此时还可以看出下面的循环也就是父进程的循环不是死循环而是只循环10次10次之后该循环就会停止也就意味着上面循环进程的父进程停止了此时该子进程就没有了相应的父进程但又可以发现当父进程停止之后此时该子进程的父进程从原来的22024变成了1这是为什么呢并且从右图可以看到此时当父进程停止之后父进程直接消失了按照之前学习的知识不是说进程停止之后会先变成僵尸状态吗这又是为什么呢 原因就是本质上一个子进程停止之后它的父进程就会把它给回收并且由于bash是所有子进程的父进程所以此时当该进程的父进程停止之后该父进程就会直接被bash进程给回收所以我们看不到该进程变成僵尸状态并且当该进程的父进程如果先停止那么此时该进程就会直接默认的被1号进程操作系统给领养使其拥有一个新的父进程所以此时该子进程就是我们所说的孤儿进程。 为什么会有孤儿进程的概念 从逆向的角度思考此时如果该进程没有新的父进程不是孤儿进程那么此时会导致什么问题呢首先明白只有父进程可以给子进程收尸其次明白不收拾会怎样得出结论如果一个子进程没有父进程就会导致无法收尸就会导致该子进程无法管理使该子进程一直在我们的内存中占空间最终导致内存泄露问题程序崩溃。 并且此时杀掉进程有两种方式一种是杀掉该进程的PIDkill -9 PID一种是直接杀掉该目标进程killall 目标进程所以你想让那个进程当孤儿进程你就杀掉谁的父进程哈哈哈哈 什么是环境变量
搞定了上述的孤儿进程的知识之后进程状态相关的知识我们就搞定的差不多了像进程中比较特殊的僵尸进程和孤儿进程我已经通过Linux下的代码进程看到了相应的场景当然进程状态中比较特殊的还有守护进程和精灵进程之类这些我们目前先不做了解接下来就让我们学习一下什么是环境变量吧 首先我们先从一个问题出发就是当我们写法代码编译之后想要运行为什么一定要加 (./) 符号呢为什么像Linux中的基本指令ls、cd、rm、cp、mv等不要呢如图 只有输入了 (./) 符号才可以执行该程序(./) 到底是什么意思呢首先要明白一点执行一条命令的前提是找到这条命令所以此时明白 (./) 的意思就是在本地寻找这个文件如果本地有该文件就执行否则就报找不到该指令同理在我们的Linux系统中也存在一个叫 PATH 的环境变量在我们输入了ls、cd、rm、cp、mv这些基本指令的时候系统会自己去PATH 的环境变量中寻找这些指令的如果环境变量中存在则执行不存在则报找不到该指令。 所以上述问题的答案就是 我们生成的可执行文件并不在系统的PATH 环境变量中想要执行该文件就要我们自己指明该文件对应的路径 (./)
搞懂了这些相信我们就明白我们是可以自己找到PATH环境变量然后把自己的可执行程序给加入到PATH环境变量中的然后在执行该程序的时候就不需要让我们自己指定路径而是让系统直接去PATH 环境变量中找该程序使我们直接输入程序名就可以不需要指明(./)了 如图 上图表示的就是使用 export 指令向PATH中写入程序路径但是要注意 此时不可以直接向PATH中写入而是要在 $PATH的后面进行插入不然会把PATH中原有的路径给覆盖掉导致出现问题不过重启软件之后可以恢复所以此时这种行为就相当于是在Linux系统中安装了一个软件所以无论是Windows还是Linux只要是安装软件本质上就是在把该软件对应的可执行文件拷贝到我们电脑相应的路径下。
查看环境变量
输入 env指令 查看Linux系统中的环境变量 在高级系统设置中查看Windows系统中的环境变量
上述有非常多的环境变量每一个都有它们对应的作用并且这些作用是非常重要的但是目前对我们来说最重要的就是上述提到的PATH搜索环境变量
查看main函数中的环境变量表
int main(int argc,char* argv[],char* envp[]) 对于以前学习C语言来说我们是不需要对main进行传参也没有函数可以调用main函数进行传参但本质上main函数是可以进行传参的并且此时由于没人可以调用main函数所以此时参数的数据就是通过命令行解释器获得就是Linux中的bash获得并且此时main函数是可以传三个参数的其中有一个就是指向环境变量表的一个字符指针数组
如图所示 所以此时main函数中的 char* envp[] 指针数组就是代表我们的环境变量表 并且此时根据图中的代码可以通过循环的方式直接将该指针数组中的指针所指向的数据进行一一打印所以如上图我们就得到了环境变量表中的所有环境变量。
并且如果不使用main函数中的参数 char* envp[] 指针数组此时也是可以获得环境变量方法就是使用函数 environ 或者 getenv 如下代码 使用该代码也可以很好的把环境变量表中的所有环境变量给打印出来跟上图是一样的此时不多加插入了 注意此时因为我们要访问的是一个指针数组所以此时需要使用二级指针所以要写成 char** environ并且加上extern表示从外部引用这样才可以很好的访问环境变量表。 此时我们就可以把环境变量表中的USER环境变量中的数据给打印出来了该函数的好处就是可以一个一个的获得我们想要的环境变量重点 所以无论是我们的user指令还是pwd指令还是cd等指令其实本质上都是通过getenv函数来实现其特定的功能的比如上述我们就自己实现了一个可以打印user的指令。 并且如果我们想要自己实现pwd和cd等指令只需要把上图代码中的user换成pwd或者cd就行了通过getenv函数我们可以直接拿到任何的环境变量实现任何的环境指令。
使用环境变量实现权限问题
如下代码充分表明了环境变量对于权限方面的使用方法可以通过环境变量中的USER来控制用户权限。
总环境变量本质就是一个内存级的一张表内存中的某块地址这张表由用户在登录系统的时候系统自动进行给特定用户形成属于自己的环境变量表并且每一个环境变量都有自己的特定使用场景。
系统如何配置环境变量
通过上述总结可以知道环境变量是系统自动帮我们配置的那么就有一个问题系统是如何进行环境变量的配置呢? 此时就涉及到了两个Linux系统中的两个文件一个是 .bash_profile 一个是 .bashrc 如图 所以在我们登录的时候系统就会自动帮我们加载上述两个文件 .bash_profile 和 .bashrc 中的配置文件将环境变量给配置完成具体原理就是将上述两个配置文件中的默认程序加载到命令行解释器bash中。
浅谈环境变量的继承
搞定了上述加载环境变量相关知识此时我们来看看环境变量的另一方面的知识环境变量的继承在理解环境变量的继承之前我们写复习一下以前的知识父进程是如何创建子进程的 如图 我们可以看到父进程在创建子进程的时候会将自己的大部分属性数据拷贝给子进程所以明白了这个道理我们就可以谈谈环境变量的继承问题了谈继承问题的第一个前提明白环境变量本质上是在命令行解释器shell、bash进程中由命令行解释器shell、bash进程控制的 所以当我们的shell进程在创建子进程的时候就会像上图一样将自己属性中的环境变量给拷贝给子进程所以这就是环境变量的继承现象并且深入理解可以发现当我们在shell中创建一个环境变量时该环境变量并不会被子进程继承只有当该环境变量被export指令写入到了环境变量表中时子进程才可以继承所以得出结论shell的本地变量只在shell内部有效不可以被子进程继承只有当使用了export把shell的本地变量导入到环境变量表后子进程才可以继承进一步说明环境变量表是在shell进程中被控制。 source(.) 让配置文件立即生效指令 什么是命令行参数
从main函数中看命令函参数int main(int argc,char* argv[]) 所以此时main函数中的int argc参数代表的就是各种的参数选项并且第一个下标永远存放的是该可执行程序myproc.
并且此时char* argv[]表示的就是如下图
给int argc;中的参数选项提供存储空间所以main函数中的两个命令函参数就是用来提供参数选项和存储参数选项的。 注意该参数选项表是由Linux中的命令行解释器bash生成的并且目的就是提供给子进程中的环境变量使用。
总int argc代表的就是命令行参数对应的个数int argv[]代表的就是各个参数对应的起始地址。
命令行参数有什么用呢
我相信大家都很好奇命令行参数到底有什么用因为平常我们使用C语言写代码的时候main函数中的参数永远是为空的表明命令行参数对于我们写C语言代码是起不到作用的本质原因也是因为我们无法去调用main函数但是当我们呢在Linux系统中时因为有了命令行解释器bash并且因为bash是所有进程的父进程所以此时命令行解释器是可以通过控制子进程的方式去控制main函数给main中的形参提供实参的所以我们把main函数中的参数就叫做命令行参数那么命令行解释器bash为什么要给main函数子进程提供参数呢或者可以说命令行解释器给main函数提供参数有什么用呢接下来我们就通过一个代码来具体看一看命令行参数给main函数传参的用处用处巨大
通过上图可以看出我们可以根据不同的命令行参数中的不同的选项让我们的同一个程序执行不同的不能本质就是if和else if 的使用所以例如我们以前使用的ls指令就是通过命令行参数的形式将自己不同的选项传递给相应的程序使用然后该程序在其内部对相应选项进行判断else if这样就可以让同一个指令软件执行不同的功能了如ls -a ls -lls -tls -b等等
进程的优先级问题
通过以前知识的学习我们可以很清楚的知道在系统当中所有的资源都是有限的导致排队是必须的有排队就会涉及优先级的问题所以让我们看一下什么是优先级或者说系统内部是怎样排队的进程的优先级PRI也就是被CPU执行的先后顺序该值越小进程的优先级越高优先级的修正数值NI表示进程可被执行的优先级的修正数值PRI值越小越快被执行加入NI之后就会变成 PRI(new) PRI(old)NI所以NI可以决定PRI调整NI就是在调整进程的优先级注意NI表示的只是进程的修正数据不是进程优先级所以本质上我们是通过修改NI的值来修改进程的优先级的如下图 可以发现输入ps -al指令我们就可以看见刚刚创建的进程的PRI和NI数据并且此时如果输入top指令我们可以看到如下图的场景 所以此时我们就可以通过这个场景来修改我们进程的优先级PRI当然本质是通过UI来修改输入r可以看到一个命令行此时就可以进行优先级的设置通过PID来设置输入PID之后你就可以看到如下图的场景 此时就可以输入你想设置的UI值了-20~19例如此时我输入了一个10此时我的UI值就变成了10进程的优先级就变成了90如下图 充分表明此时我们是可以通过UI来调整我们的进程优先级PRI并且PID的范围也必须符合UI的范围注意想要通过UI修改PRI此时的PRI每一次都是从80开始修改之后的PRI不会叠加永远从80开始
进程的特性
搞定了上述的进程的优先级的问题此时我们可以通过进程的优先级和以前学习的有关进程的相关的知识得出一些有关进程的特性
进程具有竞争性、独立性、并行、并发等特性竞争性系统进程数目众多而CPU资源有限所以进程之间是具有竞争属性的为了提高效率更合理的使用资源就有了进程优先级的概念独立性多进程运行需要独享各种资源、多进程运行期间互不干扰并行多个进程在多个CPU下分别同时进行运行并发多个进程在一个CPU下采用进程切换的方式在这一时间之内让多个进程都得以推进总结: 环境变量和我们的系统是密不可分的和我们的进程是息息相关的。