大连网站设计室,谷歌官方app下载,端游网络游戏排行榜,WordPress主题开源版文章目录 一、进程相关的一些概念1.一些常见的概念2.对于并发3.**进程切换** 二、环境变量1.PATH环境变量2.HOME环境变量3.SHELL环境变量4.env5.系统调用接口与环境变量6.什么是环境变量#xff1f;7.命令行参数8.main函数的第三个命令行参数9.如何验证环境变量是可以被继承的… 文章目录 一、进程相关的一些概念1.一些常见的概念2.对于并发3.**进程切换** 二、环境变量1.PATH环境变量2.HOME环境变量3.SHELL环境变量4.env5.系统调用接口与环境变量6.什么是环境变量7.命令行参数8.main函数的第三个命令行参数9.如何验证环境变量是可以被继承的10.本地变量与内建命令 一、进程相关的一些概念
1.一些常见的概念 竞争性: 系统进程数目众多而CPU资源只有少量甚至1个所以进程之间是具有竞争属性的。为了高效完成任务更合理竞争相关资源便具有了优先级。独立性: 多进程运行需要独享各种资源多进程运行期间互不干扰并行: 多个进程在多个CPU下分别同时进行运行这称之为并行每个CPU都有Linux内核的O(1)调度算法并发: 多个进程在一个CPU下采用进程切换的方式在一段时间之内让多个进程都得以推进称之为并发 。 2.对于并发 如下图所示当多个进程在CPU上执行的的时候CPU会让他们不断的切换但是由于CPU的速度太快所以我们看上去好像就是没有任何的影响 在进程切换的时候会有一个时间片如果在这个时间段内没有跑完这个进程那么就先让他下去让其他进程先跑。所以这样可以避免一个进程把CPU给卡死。这就是基于进程切换基于时间片轮转的调度算法 我们也在前面提到过CPU会维护两个队列。当一个进程的时间片过了以后会将这个进程从CPU上剥离下来 剥离下来以后会让这个被剥离出来的进程去另外一个队列中排队。这样的话防止还在原队列中排队却由于优先级的太高的问题又让他先执行了。 必须得先等原来的一个进程队列给跑完才能继续跑。 这也就是为什么要两个队列的原因。 3.进程切换 为什么函数返回值会被外部拿到呢 在我们返回的时候 比如return a其实就是mov eax 10将10放到eax这个寄存器中 像我们写的这个int a add(10,20) 其实就是将这个返回值写入eax寄存器中这个等号会被编译为一些mov指令然后mov指令将寄存器的值放入a中。 所以是通过CPU寄存器返回的。 像我们之前数据结构返回的时候不是返回一个结点的而是返回一个指针就是因为结点太大了。 系统如何得知我们的进程当前执行到哪行代码了 程序计数器PCeip会记录当前进程正在执行指令的下一行指令的地址 通过这个程序计数器就可以很容易的找到当前执行到哪行代码了。 实际上我们的寄存器大概分为以下几类 通用寄存器eax,ebx,ecx,edx栈帧ebp,esp,eip状态寄存器status 总之寄存器很多 那么这个寄存器扮演什么样的角色呢 寄存器也具有数据的临时保存能力注定了当前的计算机在运行时候重要的数据必须放在CPU内部因为离CPU越近存取的效率越高。单纯从硬件来考虑CPU寄存器的数据放在哪里都可以。但是离的越近效率越高。 所以主要目的还是提高效率将进程的高频数据放入寄存器中。 CPU内的寄存器里面保存的是进程相关的数据 这些进程相关的数据是随时可以被访问或者被修改的 所以CPU寄存器里面保存的是进程的临时数据-----这些数据我们称为进程的上下文数据 如何切换 进程在CPU上离开的时候要将自己的上下文数据保存好甚至带走 而保存的目的未来都是为了恢复。 所以进程在被切换的时候要做下面两件事 保存上下文恢复上下文 那么如何保存呢 我们可以定义一个结构体 struct reg_info
{int eax;int ebx;int eip;//....
}然后将这个结构体套入到PCB结构体里面 也就是说将数据放入到PCB中 不过上面这种做法是可以但是linux中实际并不是这么做的因为这样太慢了
二、环境变量 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数如我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途还有在系统当中通常具有全局特性 1.PATH环境变量
如下所示我们先简单的写一段代码 然后当我们运行的时候我们知道像我们自己写的程序是需要带上./的而系统中的那些指令却不需要 我们也知道像系统这些命令都是在系统的默认指定路径下的像这里路径的操作系统都能找到的
而像我们的命令是不在系统的指定路径下的所以找不到 那么这究竟是为什么呢都是一个目录还分个一二三
这一切的一切的原因就是因为系统为我们提供了一个环境变量这个环境变量叫做PATH
这个PATH是我们登录Xshell就天然存在的PATH
如果我们想要查看这个PATH,我们需要像下面这样做
echo $PATH在这里我们会看到很多路径路径之间用:分割
有了这些路径当我们输入指令的时候系统便会从这些路径中按照顺序依次查找。没找到就找下一个路径。找到了就执行。而我们这个正好处于/usr/bin这个路径下所以是可以找到的。
而我们前面的mycmd并不在这些路径所以就找不到就会提示找不到这个指令。
这个环境变量PATH就叫做Linux系统的指令搜索路径
这也就意味着如果我们可以有两种做法使得我们的程序直接输入名字就可以执行了 将该指令放到PATH的某条路径中将我们本路径添加到PATH中 这两种方法都是可以的第一件事我们之前做过
我们现在来做一下第二件事
我们可以这样做
PATH$PATH:xxxx//当前目录的路径然后我们就可以直接执行我们的指令了 甚至于我们把这个程序名字一改也是可以跑的因为系统自动会从当前的路径进行搜索我们输入的指令
甚至于我们的which也可以搜索到了 注意我们不可以像下面这样做这样会直接覆盖掉以前的环境变量的就会造成以前绝大部分的指令都跑不了了 不过pwd还可以跑 就是因为以前的环境变量都被覆盖了。
那么如何恢复呢其实我们这个环境变量是一个内存级别的我们只需要关闭Xshell然后重新登录即可。
也就是说都是在shell中保存的。
2.HOME环境变量
当我们用root账号显示这个环境变量的时候显示的是这样的 当我们用普通账号显示的时候是这样的 这个环境变量也正好解释了为什么我们一登陆的时候就是这个目录下。
主要原因就是在我们登录时会识别我们这个账户是谁然后给我们填充$HOME环境变量
在登录的时候默认就是cd $HOME
3.SHELL环境变量
这个环境变量可以让我们看到我们当前用的是哪个shell 4.env
除了上面的这三个环境变量其实还有很多的环境变量那么我们如何去查找呢我们可以使用env命令
这个可以看到我们系统里面的所有的环境变量 其中比如 HOSTNAME代表的就是主机名 HISTSIZE代表的是历史命令被记录下来的条数这个主要应用于我们的指令上下翻我们知道是可以看到我们以前输入的指令的而这些指令最多只能保存1000条history这条指令可以查看到我们历史的所有指令 SSH_TTY代表的就是我们当前的终端设备文件如下是它的用法 USER代表的就是我们当前的账户是谁 LS_COLORS代表的是配色方案 PWD代表的就是当前进程所代表的路径如果我们把当前路径换了这个也会随之改变所以我们可以取到我们当前的路径就是因为PWD这个环境变量会记录我们当前进程所处的工作目录 LANG是编码方案 LOGNAME指的是当前登录用户是谁 OLDPWD代表的就是进程上一次的路径这也就是cd -这条指令可以执行原因 其中对于USER和LOGNAME我们可以暂时理解为是一样的因为无论是普通用户和root用户我们现在来查看起来都是一样的 5.系统调用接口与环境变量
我们前面的方法说明了环境变量可以通过指令去查看可是我们未来的代码是不可能通过指令去查看环境变量的所以就有了系统调用接口查看环境变量
man getenv我们可以用上面这个指令去查看这些系统调用接口 我们就可以看到这个函数了
我们可以将这个环境变量的名字给这个函数然后这个函数就会返回这个环境变量的值 然后我们就可以打印出环境变量了 现在我们使用这个代码 而同一份代码当我们切换到root的时候结果也随之改变 所以说有了环境变量的存在不同的账号执行同一份代码会有不同的结果。
所以我们就可以对权限有更进一步的了解了 所以因为有环境变量的存在我们系统就能认识到这个人是谁所以就可以与文件中的拥有者所属组进行对比。进而可以实现权限
6.什么是环境变量 环境变量是系统提供的一组namevalue形式的变量不同的环境变量有不同的用户通常具有全局属性。 对于我们的系统而言存在着环境变量这个存在不因为进程的创建而存在在系统启动的时候就已经有了。默认的环境变量就是被bash先获得到。
那么环境变量具有全局属性什么是全局属性呢
像我们前面写的程序中可以使用getenv函数来获取环境变量。
那么还有没有其他方法获取环境变量呢
7.命令行参数
其实像C语言中的main函数是可以带参数的
int main(int argc,char* argv[])
{}这两个参数中arg是参数的意思c是count的意思代表右边数组的元素v是vector的意思代表一个数组。
我们使用如下代码 运行结果为 所以说实际上在执行的时候main函数会先传参。会将参数的数据进行填充 其实我们的命令行中输入的其实就是一串字符串即在bash看来就是这样的一些字符串
./mycmd -a -b -c然后bash会将这个字符串打散成四个字符串如下图所示 将这个处理好以后然后传给main函数
这个就是命令行的解析工作
那么为什么要这样做呢
我们可以使用如下代码 所以就可以产生如下效果了 而这个不就是类似于下面这种的吗 那么为什么要这样做呢 这是因为这样做可以为指令、工具、软件等提供命令行选项的支持 其实对于argv这个数组除了会命令行对应的那些字符串全部设置完毕以后还会再多开一个空间存储NULL
所以其实我们想要遍历所有的命令行参数的话我们可以不用像前面那么麻烦而是下面这样做 8.main函数的第三个命令行参数
其实main函数除了上面的两个参数以外还有第三个参数
int main(int argc, char* argv[], char* env[])
{}我们可以打印一下这个表 我们发现这个就是我们前面的env命令所打印出来的 所以说我们获取一个环境变量的时候我们不用大费周章的使用getenv了。而且它还只能用一个
所以我们的C/C代码一共是有两张向量表的
一张是命令行参数表一张是环境变量表 所以说我们的程序再运行的时候不是简单的只将程序加载到内存中而且启动的时候有人要调用main函数然后还要将这两张表给传过去 我们所运行的进程都是子进程bash本身在启动的时候会从操作系统的配置文件中读取环境变量的信息子进程会继承父进程交给我的环境变量 所以往后的所有子进程都会认识在bash中所定义的环境变量 所以说环境变量具有全局属性 我们知道环境变量也是数据进程具有独立性当我们子进程对环境变量做出修改的时候是不能影响父进程的因为会写时拷贝环境变量被继承通常有两种方式一种是直接继承一种是main函数传参 除了上面的使用第三个命令行参数的方式获取环境变量还可以使用这个第三方的变量environ来获取
extern char** environ9.如何验证环境变量是可以被继承的
当我们直接定义一个变量的时候这样的话它并不是环境变量因为在env中无法找到而是一个本地变量。
直接在bash命令行中定义的变量就是本地变量它就是一个shell层面、系统层面的概念 如果我们想要将这个变量变为环境变量我们可以这样做
export MY_VALUE123这样的话就把这个变量导出了导出到了bash的上下文中
然后在我们的程序中就可以发现了这个环境变量了 这就说明mycmd这个程序拿到了bash的环境变量
即证明了环境变量被继承了
未来它的孙子重孙子都是可以继承到这个环境变量的
如果我们要取消这个环境变量我们可以这样做
unset MY_VALUE我们前面的程序也随之找不到环境变量了 10.本地变量与内建命令
我们已经知道像这样的就是本地变量 那么如何去查呢我们可以用setset可以查到系统当中所有的变量包括本地变量环境变量
set这些本地变量是不会被继承的只会在本bash内部有效
那么什么时候需要用这些本地变量呢我们可以看到这些PS1这些的变量 这些其实就是我们命令行提示符的格式如果是普通用户就是$和root就是# 这个\的意思是如果这个命令没说完可以下一行继续说 如果是上面这样的写法会提示这样的形式我们会发现这种形式正好就是PS2这个本地变量。
所以本地变量就是需要有一些符号不希望被继承下去的。
在set中其实把环境变量去掉剩下的就都是本地变量了
就比如当我们写出如下代码的时候 直接运行是这样的 即便我们加上了本地变量仍然是不行的 唯有这样做使用export将本地变量导为环境变量就可以了 当我们不需要这个环境变量了使用unset即可 此时我们在set中也找不到了 可是我们会发现一个问题。
我们之前所说命令行中的指令都是bash的子进程那么下面的现象我们看起来似乎没有问题 但是我们之前说过这些 my是本地变量本地变量不会被继承指令都是bash的一个进程 思考以上几点感觉优点不对劲既然echo会新起一个进程而本地变量不会被继承是如何打印的本地变量呢
其实我们前面所说的指令都是bash的一个进程这句话不完全对甚至是错的
其实指令应该分为两批
常规命令通过创建子进程完成的内建命令bash不创建子进程而是由自己亲自执行类似于bash调用了自己写的或者系统提供的函数
也就是说如果是常规命令的话会有fork如果是内建命令就不会fork
与之类似的指令还有cd -指令
因为如果cd创建了子进程那么它改变的是子进程的路径父进程的路径不应该受到影响可是我们父进程的路径被修改了。
这就是因为cd也是一个典型的内建命令
在linux中有一个函数chdir就可以改变当前进程的路径 所以我们可以模拟实现一个cd命令 当我们运行的时候发现还是不可以的 这是因为我们这个./mycmd本身就会另起一个进程在它的进程里面会改变路径但是在我们当前的进程里面是不会改变的
那么我们可以将代码稍作修改然后再这个代码里面的进程先观察一下 我们可以看到当前进程的路径在改变之前是如下的 改变之后就变为了/ 如果我们现在这个程序不是我们自己写的而是bash本身。那么这个就是一个内建命令就可以实现更换目录了
也就是说类似于这样的实现假设我们当前的就是bash.c文件。直接在这里面进行特判即可就可以不用创建子进程了就可以看到目录变化了