在学完进程状态之后,本章我们将来学习一下环境变量,还有进程优先级等……
本文实验系统:CentOS 7.6
~
在之前我们讲解过什么是权限: 传送门
我们这里讲的优先级并不是权限,那么优先级到底是什么呢?
系统里面永远都是,进程占大多数,而资源是少数!所以,进程竞争资源是常态!一定需要确认先后!
Linux下的优先级的相关概念和操作(怎么办):
我们可以根据自己的需求将进程的优先级进行修改:
pri
,而是NI
数字越小,代表优先级越高,数字越大,代表优先级越低。
我们可以通过代码的方式来对优先级进行修改,但是我们只讲通过修改nice
的方式来对进程优先级进行修改。
注意:
不建议随便改Liunx系统中的优先级,因为我们并不懂调度器的调度算法,随便的更改优先级就是变相的插队,可能让我们自己写的进程优先得到了某种资源,但是可能会打破调度系统的平衡。
每次设置优先级,这个old优先级都会被恢复成为80。
一个进程的优先级不能被轻易修改,会打破调度器平衡,如果非得设置就必须具备超级用户的权限。
如果nice修改的值超出了指定的修改范围,那么就会取其上、下限。
当我们设置完该进程的pri为60之后,再次对该进程的nice进行修改,此时pri会再次恢复到80!!
竞争性: 系统进程数目众多,而CPU
资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
进程在使用资源的时候是不允许别的进程来使用的。竞争方式一:排队。
当一个进程在使用资源的时候,是不允许别的进程也来使用该资源的基本上所有的外设和CPU都是这样子的。
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰,进程运行是有独立性的。
进程运行具有独立性,不会因为一个进程挂掉或者异常,而导致其他进程出现问题!
使用STL将对象放到各种容器中,就像在Linux系统当中将PCB放来放去是一个道理。
并行: 多个进程在多个CPU
下分别,同时进行运行,这称之为并行。
我的电脑是单CPU的,但是我的电脑中有各种进程都可以在跑,这是什么原因?
此时我们不得不清楚一个概念:
多个进程都在你的系统中运行 != 多个进程都在你的系统中同时运行
这就是跑死循环不卡死的原因,可能会卡一点,因为存在进程的切换。
操作系统中的一个软件叫调度器帮我们做的将进程放在CPU再扒下来,赋予执行的时长,为什么是这么长时间等等…
并发: 多个进程在一个CPU
下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
如果存在多个CPU的情况,在任何一个时刻,都有可能有两个进程在同时被运行(就是在CPU上运行)
操作系统,就是简单的根据队列来进行先后调度的吗??有没有可能突然来了一个优先级更高的进程??
当代计算机都具有的一种机制:抢占式内核!
正在运行的低优先级进程,但如果来个优先级更高的进程,我们的调度器会直接把进程从
CPU
上剥离,放上优先级更高的进程,进程抢占。
进程抢占:
有可能进程正在跑,突然来了个优先级更高的进程,操作系统直接就把这个进程扒下来了,让优先级更高的进程来跑。
这里我们就简单介绍一下:
而我们之前学习过数据结构,我们知道队列是先进先出的,是不允许随意插入的,那么优先级如何体现出来呢?
操作系统采用的是哈希的数据结构,哈希复习:传送门
根据不同的优先级,将特定的进程放入不同的队列中!
同时操作系统还做了另外的结构优化,因为存在大量不同优先级的进程,如果遍历哈希表的话就是线性探测,这里则是运用位图来判断所需进程在不在,位图复习:传送门
操作系统会把活跃的进程放在一起,旧的进程放在一起,最后再交换指向两个哈希表的指针,就将两个哈希表交换了。
CPU
一定具有把数据暂时保存起来的能力。
CPU
内的寄存器更多是用来保存一些临时数据。
CPU
内的寄存器是:可以临时的存储数据,非常少,但是非常重要。
int func()
{
int a = 10 + 20;
return a;
}
int main()
{
int ret = func();
return 0;
}
把a的值放到了寄存器eax里面,用寄存器的方式来充当返回值,把寄存器里面的值mv到ret变量里,也就是把数据从CPU放到了内存里面。
我们把进程在运行中产生的各种寄存器数据,我们叫做进程的硬件上下文数据。
上下文在哪里保存呢?—— task struct
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
环境变量的用途:
如:我们在编写
C / C++
代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
我们之前学习的各种指令,工具,和可执行文件:
Linux
查看环境变量的方法:
环境变量
PATH
里面有多种变量,中间用冒号:
分割开,其中我们在执行某个程序时:例如在执行Is时, 当识别到有Is输入时, 会在上面的路径中一个一个的搜索,只要在特定路径下找到了Is,就会执行特定路径下的Is,执行完就停止搜索不再往后走了,换言之PATH就提供了可执行程序搜索的路径。Is或者是很多指令在PATH里面是可以被找到的。
那我们自己写的程序,生成的可执行程序之后,我们也想不通过带路径的方式像指令一样执行它,我们有两种方式:
直接mytest当做指令用,直接将可执行程序执行起来,不带路径:
方法一:直接将可执行程序拷贝到系统当中
一开始不做任何处理:
不建议自己安装,更不建议将自己的指令拷贝到Linux系统的目录下,因为会污染Linux
系统的命令池。
第二种:将mytest的所处路径也添加到环境变量里
命令行变量分两种:
定义变量可不仅仅只能在C/C++中,Linux命令行或者系统中也是可以直接定义变量的。
export导出环境变量,就可以在系统中可以查看的环境变量。
所以我们就可以通过export
将环境变量中的PATH
给改了,就可以实现不用路径直接执行可执行程序了。
但是不能通过上述方式,因为这样改的话就将全部的PATH给改了,那么其他的指令也就用不成了。
不过我们也不用过于担心,我们在命令行上设置的环境变量具有临时性的,将终端关掉重启就恢复了。
环境变量本身就在内存中存着呢,并不是以文件的方式存在的,改了也不影响,下次登录的时候会重新读取系统的配置文件,重新生成环境变量,如果想让配置的环境变量永久有效的话,是需要更改配置文件的。
系统中相关配置文件一般在:
环境变量轻易不要修改,非要改最好是新增,不要做覆盖。
前几个我们已经讲的差不多了,我们来介绍后几个:
aa叫局部变量查不到,可以通过export直接倒成环境变量,此时再查就能查到了。
查看本地变量:
set的环境变量和本地变量都能查到。
我们先来看main函数带两个参数:
#include
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
结尾我们给main
函数传递的argc,char* argv[]
是命令行参数,传递的是:命令行中输入的程序名和选项!!
命令行计算器:
#include
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc != 4)
{
printf("Usage: %s [-a|-s|-m|-d] one_data two_data\n", argv[0]);
return 0;
}
int x = atoi(argv[2]);
int y = atoi(argv[3]);
if(strcmp("-a", argv[1]) == 0)
{
printf("%d+%d=%d\n",x, y, x + y);
}
else if(strcmp("-s", argv[1]) == 0)
{
printf("%d-%d=%d\n",x, y, x - y);
}
else if(strcmp("-m", argv[1]) == 0)
{
printf("%d*%d=%d\n",x, y, x * y);
}
else if(strcmp("-d", argv[1]) == 0 && y != 0)
{
printf("%d/%d=%d\n",x, y, x / y);
}
else
{
printf("Usage: %s [-a|-s|-m|-d] one_data two_data\n", argv[0]);
}
return 0;
}
运行结果:
ls -a -l -i
不同的选项代表的含义不一样。那么命令行参数是怎么传递给main函数的呢??
#include
#include
#include
#include
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
结尾一个进程是会被传入环境变量参数的,每个进程都是的!!
我们自己的程序跑起来变成进程,这个进程就被调用方传入了环境变量了。
如果一个C语言函数在声明中没有带参数,但是我们强制给其带参的话并不报错。
而且强行传的参数,依旧压栈,依旧形成临时变量,只不过后面没有使用罢了。
给函数定义的时候形参带上void的话,强制传参才会报错。
进程想获得环境变量的第一种方法,那就是main
函数的第三个参数,传进来的值就是一个指针数组,就可以通过指针数组的方案来遍历。
int main()
{
extern char** environ;
for (int i = 0; environ[i]; i++)
{
printf("%d: %s\n", i, environ[i]);
}
return 0;
}
#include
#include
int main()
{
char* val = getenv("PATH");
printf("%s\n", val);
return 0;
}
以后有用途,万一有用途~
我们写一个只能自己运行的程序:
#include
#include
#include
int main()
{
//让程序只能自己执行
char* id = getenv("USER");
//忽略大小写
if(strcasecmp(id, "Zh_Ser") != 0)
{
printf("权限拒绝!\n");
return 0;
}
printf("成功执行...\n");
char *val = getenv("PATH");
printf("%s\n", val);
return 0;
}
环境变量是谁给我的呢??目前谈不清,但是我们可以观察到!