前言
在了解进程状态之后,本章我们将来学习一下进程优先级,还有环境变量等。。
目录
- 1.进程优先级
- 1.1 为什么要有优先级?
- 2.进程的其他概念
- 2.1 竞争性与独立性
- 2.2 并行与并发
- 2.3 进程间优先级的体现:
- 2.3.1 O(1) 调度算法:
- 2.4 进程上下文:
- 3 .环境变量
- 3.1 环境变量的概念:
- 3.2 常用的环境变量:
- 3.3 环境变量指令:
- 3.4 linux修改环境变量的方法:
- 3.5 通过代码如何获取环境变量:
- 3.5. 1 **环境变量的组织方式**
- 3.5. 2 方法一:main函数的第三个参数
- 3.5. 3 方法二:通过C语言第三方变量environ获取
- 3.5. 4 方法三:通过系统调用获取或设置环境变量
- 3.6 环境变量通常是具有全局属性的
1.进程优先级
1.1 为什么要有优先级?
因为CPU是有限的,进程太多,需要通过某种方式竞争资源!Linux系统中进程占大多数,而资源是少数! 所以,进程竞争资源是常态!一定需要确认先后顺序
- cpu资源分配的先后顺序,就是指进程的优先权(priority)。
- 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
- 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能
- 什么是优先级?
就是确认是谁应该先获得某种资源,谁后获得
在Linux系统中,一般一个服务,是专属专机。优先级是操作系统是最清楚的(在创建进程task_struct时),你自己改的,并一定按照这个操作来的。(一般不需要调整的)
计算机为了保证每个进程能够,尽可能平均的使用进程,所以nice的调整范围只有40个。(-20~ 19)
- Linux优先级的构成
- priority(PRI) + nice
PRI(new)=PRI(old)+nice - 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进 程的优先级变化。
- 可以理解nice值是进程优先级的修正修正数据
注意:
-
虽然我们可以对Linux进程的优先级进行修改
-
但是Linux不允许进程无节制的设置优先级
-
用top命令更改已存在进程的nice
输入top
进入top后按“r”–>输入进程PID–>输入nice值
-
nice值的修改并不是无节制的,是有一定取值范围的;nice [-20, 19] prio [60,99]
-
当我们设置完该进程的pri为60之后,再次对该进程的nice进行修改,此时pri会再次恢复到80!!
prio = prio_old + nice
2.进程的其他概念
2.1 竞争性与独立性
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
当一个进程在使用资源的时候,是不允许别的进程也来使用该资源的基本上所有的外设和CPU都是这样子的。
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰,进程运行是有独立性的。
进程运行具有独立性,不会因为一个进程挂掉或者异常,而导致其他进程出现问题!
使用STL将对象放到各种容器中,就像在linux系统当中,将PCB放来是一个道理。
2.2 并行与并发
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
- 不要以为进程一旦占有CPU,就会一直执行到结束,才会释放CPU资源!
- 我们遇到的大部分操作系统都是分时的
- 在一个时间片内,多个进程都会通过切换交叉的方式,让多个进程代码,在一段时间内,都得到推进
- 例如一个进程,只能在CPU内执行10ns ,就要从CPU上扒下来,让其他的进程来执行
- 这种现象,叫做并发
2.3 进程间优先级的体现:
操作系统,就是简单的根据队列来进行先后调度的嘛,有没有可能突然来了一个优先级更高的进程。。
当代计算机都具有的一种机制:抢占式内核!
正在运行的低优先级进程,但如果来个优先级更高的进程,我们的调度器会直接把进程从CPU上剥离,放上优先级更高的进程,进程抢占。
进程抢占:
有可能进程正在跑,突然来了个优先级更高的进程,操作系统直接就把这个进程扒下来了,让优先级更高的进程来跑。
2.3.1 O(1) 调度算法:
这里我们就简单介绍一下:
- 允许不同优先级的进程存在
- 相同优先级的进程,是可能存在多个的!
而我们之前学习过数据结构,我们知道队列是先进先出的,是不允许随意插入的,那么优先级如何体现出来呢?
操作系统采用的是哈希的数据结构.
根据不同的优先级,将特定的进程放入不同的队列中!
2.4 进程上下文:
CPU一定具有把数据暂时保存起来的能力。
CPU内的寄存器更多是用来保存一些临时数据。
CPU内的寄存器是:可以临时的存储数据,非常少,但是非常重要。
int func()
{
int a = 10 + 20;
return a;
}
int main()
{
int ret = func();
return 0;
}
我们把进程在运行中产生的各种寄存器数据,我们叫做进程的硬件上下文数据
- 当进程被剥离:需要保存上下文数据
- 当进程恢复的时候:需要将曾经保存的上下文数据恢复到寄存器中
上下文在哪里保存呢?—— task struct
task_struct- PCB的一种
在Linux中描述进程的结构体叫做task_struct。
task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息
3 .环境变量
3.1 环境变量的概念:
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有 在系统当中通常具有全局特性。
3.2 常用的环境变量:
- PATH : 指定命令的搜索路径
- HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
- SHELL : 当前Shell,它的值通常是/bin/bash
3.3 环境变量指令:
显示某个环境变量值:echo $path
echo $NAME //NAME:你的环境变量名称
查看系统的所有环境变量:env
设置一个新的环境变量:export / (直接使用环境变量名)如 :Path
unset: 清除环境变量
Set: 显示本地定义的shell变量和环境变量
Linux export :命令用于设置或显示环境变量
解释:
环境变量PATH里面有多种变量,中间用冒号:分割开,其中我们在执行某个程序时:例如在执行Is时, 当识别到有Is输入时,
会在上面的路径中一个一个的搜索,只要在特定路径下找到了Is,就会执行特定路径下的Is,执行完就停止搜索不再往后走了,换言之PATH就提供了可执行程序搜索的路径。Is或者是很多指令在PATH里面是可以被找到的。
3.4 linux修改环境变量的方法:
-
方式1:
export PATH=$PAHT:/home/路径
//临时修改,只对当前终端生效,立即生效 终端一关闭,就失效了 -
方式2:
修改 家目录下的 .bashrc 文件
这个文件每个用户都有,都放在自己的家目录下
用户每次登录时,都会加载(执行)这个文件
所以,将export XXX=$XXX:xxx 放到.bashrc这个文件中
就会对当前用户一直生效了
修改.bashrc文件后 需要重新登录(重新打开终端 才会生效)
或者 执行 source .bashrc 就可以立即生效了 -
方式3:
-修改系统时会加载的文件 如 /etc/environment 或者 /etc/profile
因为这些文件在系统启动时候会被执行
所以在这些文件中修改环境变量,没次启动系统都生效
因为用户修改环境变量时 都是以 PATH=$PATH:的方式追加的
所以每个用户第一次修改时取的基本变量值都是他
所以修改这些文件,是对所有用户有效的
重启生效
或者执行 source /etc/profile source /etc/environment 生效
3.5 通过代码如何获取环境变量:
-
main函数可以带参数吗?可以带多少?
我们先来看main函数带两个参数:
#include <stdio.h>
int main(int argc, char* argv[])
{
int i = 0;
for(i = 0; i < argc; i++)
{
printf("argv[%d]: %s\n", i, argv[i]);
}
return 0;
}
- char* argv[]是个指针数组,而int argc则是指针数组中元素的个数。
- 可执行程序和选项都是字符串,最后都以指针数组的方案存在了指针数组中。
- 指针数组中存的是字符串的起始地址
- 最后以NULL(’\0’)结尾
3.5. 1 环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
3.5. 2 方法一:main函数的第三个参数
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
void func(void)
{
printf("hehe\n");
}
int main(int argc, char* argv[], char* env[])
{
//func(1, 1);
int i = 0;
for(i = 0; env[i]; i++)
{
printf("env[%d]: %s\n", i, env[i]);
}
return 0;
}
- char* env[]也是个指针数组
- 数组里的每个元素都是指向一个字符串,每个字符串就是一个环境变量
- 最后以NULL结尾
3.5. 3 方法二:通过C语言第三方变量environ获取
int main()
{
extern char** environ;
for (int i = 0; environ[i]; i++)
{
printf("%d: %s\n", i, environ[i]);
}
return 0;
}
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。
3.5. 4 方法三:通过系统调用获取或设置环境变量
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%s\n", getenv("PATH"));
return 0;
}
常用getenv和putenv函数来访问特定的环境变量。
3.6 环境变量通常是具有全局属性的
- 环境变量通常具有全局属性,可以被子进程继承下去。
- 如果只进行 MYENV=“helloworld” ,不调用export导出,在用我们的程序查看,会有什么结果?为什
么? 普通变量 不会被子进程继承下去
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * env = getenv("MYENV");
if(env){
printf("%s\n", env);
}
return 0;
}
直接查看,发现没有结果,说明该环境变量根本不存在
导出环境变量 export MYENV=“hello world”
再次运行程序,发现结果有了!说明:环境变量是可以被子进程继承下去的!想想为什么
尾声
看到这里,相信大家对这个C++有了解了。
如果你感觉这篇博客对你有帮助,不要忘了一键三连哦