1.环境变量
1.1 基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
- 环境变量会被继承下来,父进程的环境变量会继承给子进程。
1.2 常见环境变量
- PATH : 指定命令的搜索路径
- HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
- SHELL : 当前Shell,它的值通常是/bin/bash。
1.3 查看环境变量

env指令可以查看所有环境变量。

echo+$环境变量名称 :可以查看环境变量。
1.4 进一步了解环境变量


为什么我们输入ls,cd,pwd这些指令的时候,就可以直接被执行,但是我们的二进制文件却需要输入./文件名才会被执行呢?
- Linux 中的各种指令都是用 C语言 编写的程序,所以:运行指令 == 运行程序
- PATH 环境变量中有存储各种指令(程序)的路径,当我们直接输入指令时,OS会根据 PATH 提供的路径搜索程序,找到了就会直接运行对应指令(程序)
- 而我们自己编写的程序则是需要通过 ./可执行程序 的方式运行,因为此时路径不被包含在 PATH 变量中。
- 总之:PATH 存储路径中若包含程序,可以直接通过程序名运行程序这就是各种指令,如 ls、pwd、touch 的运行原理。
我们可以输入export PATH=$PATH:/home/wjp/lee,把路径添加到系统的搜索路径中,这样子再执行的时候就会去这条路径里面寻找。

export PATH=/home/wjp/lee,如果这样子写的话就会变成覆盖掉了,输入其他指令都不会生效。

如果覆盖了也没有关系,普通用户的操作在重启后就会恢复原来的路径,切换到root用户的话要小心使用。
1.5 本地变量


当我们直接将1234赋值给myval,就是一个本地变量,是不会被继承的,同时也不属于环境变量,在env里面也查找不到这个环境变量,也就是这个本地变量是只属于bash的。

通过在环境变量前面加是export可以将它变为环境变量。

set指令可以把所有的本地变量和环境变量全部显示出来。
1.6 环境变量的相关指令
- echo: 显示某个环境变量值

- export: 设置一个新的环境变量

-
env: 显示所有环境变量
-
unset: 清除环境变量

环境变量中找不到a了。
- set: 显示本地定义的shell变量和环境变量
1.7 环境变量的获取

每个程序都会收到一个环境变量表,环境表是一个字符指针数组,每一个指针都指向一个以'\0'结尾的环境字符表。
1.7.1 通过代码获取环境变量
int argc 传入程序中的元素数,./程序名 算一个
char* argv[] 传入程序中的元素表,由 bash 制作,传给 main 函数

cpp
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 int main(int argc,char*argv[])
5 {
6 int i=0;
7 for(;argv[i];i++)
8 {
9 printf("env[%d]->%s\n",i,argv[i]);
10 }
11 return 0;
12 }

所以我们在命令行输入运行指令,以空格为分隔符,bash会把这些字符都传入给argv数组,我们也就可以把它们一个一个打印出来,argc表示个数。
除了命令行参数表,mian函数还有一个char* env[] 环境变量表,所谓全局性就是指 main 函数可以通过此参数获取到环境变量表的信息。
我们同样可以通过上面的方法,把环境表都打印出来。
cpp
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 int main(int argc,char*argv[],char*env[])
5 {
6 int i=0;
7 for(;env[i];i++)
8 {
9 printf("env[%d]->%s\n",i,env[i]);
10 }
11 return 0;
12 }

1.7.2 通过第三方变量environ获取
cpp
#include <stdio.h>
int main(int argc, char *argv[])
{
extern char **environ;
int i = 0;
for(; environ[i]; i++){
printf("%s\n", environ[i]);
}
return 0;
}
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。
1.7.3 通过系统调用获取环境变量
前面两个都是获取了整个的环境变量表,如果我们需要在代码中获取单一的环境变量可以使用getenv()函数

cpp
int main()
{
printf("%s\n", getenv("PATH"));
return 0;
}
1.8 常规命令和内建命令

前面我们提到本变量是不会被继承的,那么bash不是通过创建进程来帮助自己实现指令的吗,echo函数的实现难道不是bash创建子进程来帮助完成的吗?
答案是不是的,指令页分为两种:
常规命令:bash通过创建子进程来完成的。
内建命令:bash不创建子进程,而是自己亲自执行,类似于bash调用了自己写的函数,或者系统调用函数。
2. 进程优先级
cpu资源分配的先后顺序,就是指进程的优先权(priority)。
优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

我们很容易注意到其中的几个重要信息,有下:
- UID : 代表执行者的身份
- PID : 代表这个进程的代号
- PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
- PRI :代表这个进程可被执行的优先级,其值越小越早被执行
- NI :代表这个进程的nice值
PRI and NI
- PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
- 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
- PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice,
- 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
- 所以,调整进程优先级,在Linux下,就是调整进程nice值
- nice其取值范围是-20至19,一共40个级别。
- 所以最后就看PRI(new)越小优先级就越高
PRI vs NI
- 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
- 可以理解nice值是进程优先级的修正修正数据
2.1 top指令
进入top后按"r"-->输入进程PID-->输入nice值
操作系统的分配已经是最优的方法了,所以我们就不应该过多的去修改。
注意:
- NI值区间为 [-20, 19],设置时超出部分无效
- 修改优先级时,最终优先级 = 初始优先级 + NI值,优先级的修改行为并不是连续的,每次都是在最开始的基础上进行修改(默认为 80)
- 调度器不允许存在 优先级失衡 的情况,因此优先级修改不能太激进。
一些其他概念
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发
寄存器:寄存器有很多种,去保存进程里面很多相关的数据(相当于进程的上下文),当进程被切换,需要做的有保存上下文,和恢复上下文,这样子 cpu 才会知道你接下来该运行哪个部分,和上面的上次运行时的数据,保存上下文,进程要时间片时间到了后,要脱离 cpu,进程的 pcb 会构建一个结构体,里面去存放上下文,到再次要运行的时候,再把数据放到寄存器上面(这个是当前只能这么理解)。