🥁作者: 华丞臧.
📕专栏:【LINUX】
各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞+收藏+关注
)。如果有错误的地方,欢迎在评论区指出。
推荐一款刷题网站 👉 LeetCode刷题网站
文章目录
- 前言
- 一、Linux中进程优先级
- 1.1 基本概念
- 1.2 查看系统进程
- 1.3 查看进程优先级的命令
- 1.4 其他概念
- 二、Linux中的环境变量
- 2.1 基本概念
- 2.2 常见环境变量
- 2.3 查看环境变量
- 2.4 测试环境变量
- 2.4.1 测试PATH
- 2.4.2 测试HOME
- 2.5 环境变量的相关命令
- 2.6 环境变量的组织方式
- 2.7 获取环境变量
- 2.7.1 main函数参数
- 2.7.2 第三方变量environ获取环境变量
- 2.7.3 系统调用获取或设置环境变量
- 2.8 环境变量和本地变量
前言
操作系统具有进程管理的功能,可以同时管理多个进程,但是系统里永远都是进程占大多数而资源是少数;那么当多个进程同时响应时,操作系统该如何选择呢,因此进程之间需要区分优先级;同时,操作系统也是一款软件一个进程,那么在操作系统的源代码中一定存在一些参数用来指定操作系统的运行环境,而这些参数被称为环境变量。
一、Linux中进程优先级
1.1 基本概念
优先级是进程获取资源的先后顺序。
- 本质是资源不足,CPU资源分配的先后顺序,就是指进程的优先权;
- 优先权高的进程有优先执行权,配置进程优先权对多任务环境的Linux很有用,可以改善系统性能;
- 优先级还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
1.2 查看系统进程
在Linux系统中,用以下命令会输出一下几个内容:
- ps -l:显示当前终端下的进程信息;
其中重要信息如下:
- UID:代表执行者的身份;
- PID:代表这个进程的代号;
- PPID:父进程代号,代表这个进程是由哪个进程发展衍生而来的;
- PRI:代表这个进程可被执行的优先级,其值越小越早被执行;
- NI:代表这个进程nice值。
- ps -la
PRI && NI
- PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是进程被CPU执行的先后顺序,这个值越小进程优先级越高;
- NI也就是nice值,相当于副优先级,其表示进程可被执行的优先级的修正数值;
- PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new) = PRI(old) + nice;
- 当nice值为负值时,该进程优先级值将会变小,其优先级会变高,进程越快被执行;
- nice取值范围在-20~19,一共40个级别。
PRI vs NI
- 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化;
- 可以理解nice值是进程优先级的修正修正数据
1.3 查看进程优先级的命令
- top:普通用户必须要提权成为超级用户才能使用top修改进程NI优先级,并且其范围在-20~19之间;
- 进入top后按“r”–>输入进程PID–>输入nice值;
- 每次重新设置nice值的时候,PRI都会重新设置为80(系统默认值),然后再加上nice值;
修改之前:
修改nice为-100,发现NI的值并不是-100而是-20:
修改nice为100,发现NI的值并不是100而是19:
为什么nice值的范围在-20~19呢?
首先Linux系统一共有140个优先级,很多优先级不是给普通的进程使用的,60~99这40个优先级是给用户使用的;Linux系统不允许用户随意修改进程优先级,因为操作系统有很多系统需要的进程,他们维持着操作系统的运行,如果用户能随意修改优先级,就可能导致系统的进程优先级过低,造成系统进程不能及时运行而使用操作系统性能降低。
1.4 其他概念
- 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高
效完成任务,更合理竞争相关资源,便具有了优先级 ; - 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰;进具有独立性,不会因为一个进程挂掉或者异常,而导致其他进程出现问题;
- 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行;
- 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发;
并行 && 并发
CPU能同时运行多个进程吗?答案是不能,一个CPU在同一时刻只能运行一个进程。
- 并行就是指在多个CPU中运行多个进程,一个CPU运行一个进程。
- 并发是指在一个时间段内,多个进程会通过切换交叉的方式,在一个CPU上让多个进程代码在一段时间内都得到推进。
我们遇到的大部分操作系统都是分时的,简单来说就是每一个进程都可以在一小段时间片中占有CPU资源,每个进程的这一小段时间片形成一段时间;时间片是一段非常非常小的时间段,相对于CPU是慢的,但对于人来说是非常非常快的。时间片的分配是操作系统中软件模块调度器分配的。
进程抢占:操作系统不是完全根据队列来进行先后调度的,如果突增优先级更高的进程,调度器会将正在进行的进程从CPU上剥离下去,并将优先级更高优先级的进程加载到CPU上。
补充:操作系统会根据不同的优先级(队列是先进先出的,不能进行中间插入删除操作),将特定的进程放入到不同的队列中。
进程间切换
CPU内的寄存器作用是:可以临时存储数据,非常少但非常重要。
CPU中寄存器分为可见寄存器和不可见寄存器;当进程在被执行的过程中,一定会存在大量的临时数据,这些数据会暂存在CPU内的寄存器中;寄存器中存放的是进程在运行中产生的上下文数据,当进程被剥离时,需要保存该进程的上下文数据;当进程恢复的时候,需要将曾经保存的上下文数据恢复到寄存器中。
上下文数据:进程在运行过程中产生的各种寄存器数据,我们叫做进程的硬件上下文数据。上下文数据存放在进程PCB(tast_struct)当中。
二、Linux中的环境变量
2.1 基本概念
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数;
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但 是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
2.2 常见环境变量
- PATH:指定命令的搜索路径;
- HOME:指定用户的主工作目录;
- SHELL:当前Shell,它的值通常是/bin/bash。
Linux中的指令本质是软件,即编译好的可执行程序,那么我们发现我们自己编写的代码生成的可执行程序不能像Linux当中的指令那样使用,而是需要加上路径才行,如下图:
Linux系统的指令可以不带路径直接使用,这是得益于环境变量PATH;当我们使用系统指令时,操作系统会去PATH中保存的路径中查找指定的指令,找到了直接使用,没找到报错。
如下图,找到了直接使用:
没找到报错,如下图:
PATH中保存系统中存放指令程序文件的路径。
Linux中的系统指令一般存放在 /usr/bin
中,如下图:
2.3 查看环境变量
echo $NAME
:NAME指你的环境变量名称;
env
:显示所有的环境变量。
2.4 测试环境变量
2.4.1 测试PATH
将指定程序的路径加入到PATH环境变量中去,再不加路径运行指定的程序,此时程序是可以运行的,修改PATH指令如下:
//其中$表示当前PATH中的值,即PATH中保存的所有路径;
//:是路径分隔符;
export PATH=$PATH:[路径]
//下面的指令也可以修改PATH,只不过指定路径会覆盖PATH中保存的路径;
export PATH=[指定路径]
注意:这种修改环境变量的方式,重启客户端就会刷新,即恢复系统成为默认的PATH。
2.4.2 测试HOME
2.5 环境变量的相关命令
Linux命令行中,可以定义变量;
export
功能:设置一个新的环境变量,也可以在已有的环境变量中追加新的值;
格式:export 环境变量名=($环境变量名:)[追加值]
设置一个新的环境变量:
set
功能:显示本地定义的shell变量(本地变量)和环境变量;
格式:set | grep 变量名
,通常与grep连用。
本地变量和环境变量:
命令行中可以定义变量,变量分为本地变量和环境变量;
查看本地变量:
unset
功能:清除环境变量;
格式:unset 变量名
2.6 环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串,环境表必须以NULL结束。
2.7 获取环境变量
2.7.1 main函数参数
首先要知道main函数是可以带参数的。
//main函数可以带三个参数
//argc:(argv)数组当中元素的个数
//argv[]:数组当中的各种参数,必须以NULL结束
//env:存放环境变量的地址
int main(int argc, char *argv[], char *env[])
{}
//例子code.c
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 0;
while(argv[i] != NULL)
{
printf("%d: %s\n", i, argv[i]);
++i;
}
//printf("%d:%s\n", argc, argv[argc]);
return 0;
}
当我们实际进行命令行输入时,输入的程序名和后面的相关选项存放在main函数的参数当中,也就是argv[argc]中(以空格为分隔符),注意argv数组必须以NULL空指针结尾。
我们称传递给main函数的int argc、char *argv[]为命令行参数。
命令行参数可以让我们对同一个程序,通过传递不同的参数,使同一个程序有不同的执行逻辑或者执行结果。
获取环境变量还可以通过main函数第三个参数获取,代码如下:
注意:C语言中无参的函数可以传参数过去并且不会报错。
//env.c
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
(void)argc; //去除警告(代码中没有使用该变量会有警告)
(void)argv;
int i = 0;
for(; env[i]; i++)
{
printf("%s\n", env[i]);
}
return 0;
}
可以看到程序成功获取到了环境变量,那么这些变量为什么可以获取到呢?
结论:命令行中运行的进程都是bash的子进程,而环境变量是具有全局属性,因此bash中的环境变量会被子进程继承,所以命令行上运行的进程可以获取环境变量。
2.7.2 第三方变量environ获取环境变量
C语言会给我们定义了一个全局的第三方变量environ,可以environ中获取所有的环境变量:
#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;
}
2.7.3 系统调用获取或设置环境变量
getenv
系统调用接口可以通过指定的环境变量名获取指定的环境变量。
#include <stdio.h>
#include <stdlib.h>
int main()
{
const char *usr = getenv("USER"); //获取当前用户名
printf("%s\n", usr);
return 0;
}
2.8 环境变量和本地变量
- 环境变量通常是具有全局属性的,可以被子进程继承下去。
- 环境变量的最大意义:标识当前使用的Linux用户。
- 所谓的本地变量,本质就是在bash内部定义的变量,不会被子进程继承下去。
//code2.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * env = getenv("MYENV");
if(env)
{
printf("%s\n", env);
}
return 0;
}
通过上面程序的运行结果,可以很好的说明环境变量具有全局性可以被子进程继承,而本地变量不能被子进程继承。
需要注意Linux下大部分命令是通过子进程的方式执行的,但是还有一部分命令不通过子进程的方式执行,而是由bash自己执行(调用自己对应的函数来完成特定的功能),我们把这种命令称为内建命令。
如下图:echo和cd就是内建命令。
cd ..
应该改变子进程的工作目录但实际上cd改变的是bash父进程的工作目录。