【Linux】四、Linux 进程概念(三)

简介: 目录七、进程优先级7.1 基本概念7.1.1 什么是优先级7.1.2 为什么存在优先级7.1.3 Linux 优先级特点7.2 查看系统进程7.3 PRI 和 IN7.4 查看进程优先级和更改进程优先级7.5 其它概念7.6 进程切换八、环境变量8.1 环境变量基本概念8.2 常见环境变量8.3 查看环境变量8.4 和环境变量相关的命令8.5 测试PATH8.6 测试HOME和SHELL8.7 通过系统调用获取环境变量 8.8 环境变量通常是具有全局属性的8.9 命令行参数8.10 第三方变量 environ

目录

七、进程优先级

7.1 基本概念

7.1.1 什么是优先级

7.1.2 为什么存在优先级

7.1.3 Linux 优先级特点

7.2 查看系统进程

7.3 PRI 和 IN

7.4 查看进程优先级和更改进程优先级

7.5 其它概念

7.6 进程切换

八、环境变量

8.1 环境变量基本概念

8.2 常见环境变量

8.3 查看环境变量

8.4 和环境变量相关的命令

8.5 测试PATH

8.6 测试HOME和SHELL

8.7 通过系统调用获取环境变量

8.8 环境变量通常是具有全局属性的

8.9 命令行参数

8.10 第三方变量 environ 获取环境变量


七、进程优先级

基本概念

7.1.1 什么是优先级

       优先级实际上就是获取某种资源的先后顺序,而进程优先级实际上就是进程获取CPU资源分配的先后顺序,就是指进程的优先权(priority)

注:优先级和权限是不同的概念,权限决定的是一件事情能不能做,优先级是在权限允许的前提下,该事情先做还是后做

7.1.2 为什么存在优先级

       优先级存在的主要原因就是资源是有限的,而存在进程优先级的主要原因就是CPU资源是有限

7.1.3 Linux 优先级特点

       优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能

       进程优先级本质就是 PCB 结构体里面的一个数字(其他OS也可能是几个),比如吃饭排队,给排队的每一个人一个编号,到哪个编号服务员就喊哪个编号

7.2 查看系统进程

在Linux或者Unix操作系统中,用 ps -l 命令会类似输出以下几个内容

ps -l

image.png

注意到其中的几个重要信息,有下:

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行(priority
  • NI :代表这个进程的nice值

进程的优先级就与 PRI 和 NI 有关,Linux支持进程进行中进行优先级的调整,调整的策略是通过更改 NI(nice值)完成的

最终优先级 = 老的优先级 + nice值

7.3 PRI 和 IN

  • 进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
  • nice值 其表示进程可被执行的优先级的修正数值
  • PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为: PRI(new)=PRI(old)+nice
  • ice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
  • 调整进程优先级,在Linux下,就是调整进程nice值
  • nice其取值范围是-20至19,一共40个级别
  • 在Linux中,PIR 的默认值是 80

所以,在Linux中,最终优先级PIR = 80 + nice值,PRI(old)默认是 80

注意:

  1. 进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化
  2. 可以理解nice值是进程优先级的修正修正数据

7.4 查看进程优先级和更改进程优先级

测试代码

#include<stdio.h>    #include<unistd.h>    intmain()    
{    
while(1)    
    {    
printf("PID:%d\n", getpid());    
sleep(2);                           
    }    
return0;    
}    

运行进程,查看优先级

ps -al

image.png

在Linux操作系统中,初始进程一般优先级PRI默认为80,NI默认为0

然后通过 top 命令更改进程的nice值,top进入top后按“r”–>输入进程PID–>输入nice值

top

image.png

top 命令就相当于Windows操作系统中的任务管理器

然后按 r

image.png

输入你要调整进程的优先级的 PID,然后回车

image.png

之后输入 nice值后按“q”即可退出,如果我这里输入的nice值为15,再次查看,发现 6845进程的进程优先级 PIR 发生了改变,IN 也发生了改变

image.png

注意:

若是想将NI值调为负值,也就是将进程的优先级调高,需要使用sudo命令提升权限

image.png

sudotop

image.png

有权限之后就可以调高进程的优先级了

image.png

注意:nice其取值范围是-20至19,你写 nice值超过19,默认为19,比如你输入50,nice 值最高依旧是19,-20也是如此。PRI(old)默认值是 80,不会发生改变

7.5 其它概念

  • 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。就比如你运行的抖音崩溃了,但是不会影响 qq的进程运行,进程运行各不干扰,不会说抖音运行崩溃了会导致你QQ运行崩溃。独立性后面讲到进程地址空间的时候再深入理解
  • 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
  • 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

解释并发:

       假设在只有一个 CPU 的情况下,我们发现也能同时运行几个或多个进程,比如你运行了浏览器,但是又可以运行QQ ,也可以打开PDF阅读器...不是说一个CPU只能运行一个进程么?为什么你又可以运行多个进程?

       一个运行中的进程,CPU 不会说一直等它运行结束才运行下一个进程。当代计算机采用的是 “时间片轮转” 的策略,规定每个进程在 CPU 上运行是有一定时间限制的。假设每个进程运行时间片是 10毫秒,CPU 一秒钟就能运行 100 个进程。即使进程没有运行完,也要把进程从 CPU 上拿下来,重新放在运行队列尾部继续排队,再次等待 CPU 运行。这就解释了一个CPU 可以运行多个进程的 “现象”,这种现象就叫并发

7.6 进程切换

       CPU 内是有一套寄存器硬件的,其中一个 pc 或叫 eip 寄存器的作用是:保存当前正在执行指令的下一条指令的地址

CPU 永远做着三件事:

  1. 取指令
  2. 分析指令
  1. 执行指令

       当进程在 CPU 上运行的时候,会产生很多的临时数据,这些数据是属于当前进程的,这些数据并且保留在 CPU 的寄存器上

注意区分:CPU 内部虽然有一套寄存器硬件,但是,寄存器内保留的数据是属于当前进程的。寄存器硬件 != 寄存器内的数据

       上面的并发谈到,进程在 CPU 上运行是,该进程占用 CPU,进程不是一直占用 CPU 到进程结束,而是说,进程运行的时候,有属于自己运行的时间片。当进程运行时间达到时间片后,就会从 CPU上拿下来。

       进程被拿下来到下一次进入CPU 运行也要被恢复,怎么恢复?

       进程被 CPU 拿下来了,该进程运行时产生的临时数据也要保留,这里就暂且说临时数据保留在 PCB 里面吧(这里保留在PCB不太对,这里暂且这么理解)

       等到进程下一次运行的时候,之前保留在的数据要被恢复。

举个栗子:比如你在大一要去当兵,去当兵你的学校会把你的学籍保留下来,等你从部队回来了,你的学籍就要被恢复才能继续读书。这里的学校就相当于 CPU,你就相当于一个进程,部队就相当于一个等待队列,学籍就相当于在上一次运行是产生的临时数据。你从部队回到学校继续读书就相当于进程再一次进入 CPU 内运行,这一个过程就叫进程切换

       进程在切换的时候,要对进程的上下文保护,这里的上下文指的就是寄存器内的临时数据,不是寄存器。当进程在恢复运行的时候,要进行上下文恢复


   在任何时刻,CPU 内里面寄存器的数据,看起来是在大家都能看见的寄存器上,但是,寄存器内的数据只属于当前进程。寄存器被所有进程共享,但寄存器内的数据,是每个进程各自私有的,这些私有的数据叫上下文数据

八、环境变量

8.1 环境变量基本概念

       我们所写的代码生成的可执行程序,这个可执行程序就是一个命令,不过我们要加 “./” 才能运行它。我们使用的 Linux命令本质就是一些可执行程序,不过执行它们,不用加 “./” 就可以直接运行这些可执行程序

image.png

我们可以使用 file 命令查看一下

1. file mytest
2. //mytest 是你的可执行程序

image.png

也可以使用 file 命令查看一下Linux 的命令

image.png

为什么我们写的可执行程序要加 “./” 才能运行,而Linux的命令却不用加 “./” 就能运行?它们同样是可执行程序

这就与环境变量有关系了,我们也可以把 mytest 可执行程序放入 /usr/bin/ 路径下,不用加 “./” 也能直接运行 mytest,但是这种做法不推荐,你写的程序没有经过测试,可能会污染命令池

       环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数

如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

8.2 常见环境变量

  • PATH : 指定命令的搜索路径
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,,默认的目录)
  • SHELL : 当前 Shell,它的值通常是/bin/bash

这些下面解释

windows下也有环境变量,“我的电脑” -> 右键 -> 属性 -> 高级系统设置

image.png

8.3 查看环境变量

env 命令

env   //显示所有环境变量

image.png

查一个具体的环境变量路径

echo $NAME //NAME:你的环境变量名称

比如查看,PATH、HOME,找到的话会打印出来,以冒号分隔

image.png

8.4 和环境变量相关的命令

  • echo: 显示某个环境变量值
  • export: 设置一个新的环境变量
  • env: 显示所有环境变量
  • unset: 清除环境变量
  • set: 显示本地定义的shell变量和环境变量

8.5 测试PATH

PATH : 指定命令的搜索路径

我们所在 Linux 执行的每一条指令,都会通过这个环境变量 PATH 进行检索,找到了指令就运行它,找不到就说没有这个命令

image.png

上面也提到,为什么我们写的可执行程序要加 “./” 才能运行,而Linux的命令却不用加 “./” 就能运行?它们同样是可执行程序

image.png

系统就是通过环境变量 PATH 来找到相关命令的,比如上面的 ls、mytest,环境变量会在系统的路径下查找该命令, 找到就执行,找不到就说没有

用 echo $ 查看环境变量PATH我们可以看到如下内容

[fy@VM-4-14-centos d1]$ echo $PATH

image.png

   可以看到环境变量PATH当中有多条路径,这些路径由冒号隔开,比如当你使用 ls命令时,系统就会查看环境变量 PATH,然后默认从左到右依次在各个路径当中进行查找,而 ls 命令实际就位于 PATH当中的某一个路径下,所以就算 ls 命令不带路径执行,系统也是能够找到的,这就是因为 ls 命令处于环境变量 PATH 的路径下

       这也说明了为什么我们直接执行我们写的可执行程序 mytest 不可以,因为我们写的可执行程序 mytest 不在环境变量 PATH 的路径下,我们想执行我们写的可执行程序就必须加上 “./” ,它的作用就是帮我们在当前路径下找到该可执行程序并执行它

那可不可以让我们自己的可执行程序也不用带路径就可以执行呢?

当然可以,下面给出两种方式:

方式一:将可执行程序拷贝到环境变量PATH的某一路径下

       上面也说了,这种做法不推荐,你写的程序没有经过测试,可能会污染命令池

image.png

方式二:将可执行程序所在的目录导入到环境变量PATH当中

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

使用命令 export PATH=$PATH:当前路径  

export PATH=$PATH:/home/fy/CODE_lqh/code_linux/code_12_05/d1

image.png

这样就可以直接运行当前路径下的可执行程序了

image.png

更改环境变量,只对本次登录有效,只要不动配置文件,咋搞都没问题,下次登录又会重新生成新的环境变量

那问题又来了,系统的环境变量哪里来的呢?

进入系统目录 cd ~

image.png

系统定义环境变量就在这两个文件里面定义

image.png

我们在登录的时候,当前系统的 bash 进程默认会把这两个文件执行一次,也就是把环境变量导入到你当前的环境当中,你把当前的环境变量覆盖了,重新登录又会生成新的环境变量,这些环境变量都是具有全局属性的,每一个环境变量都有自己的功能

8.6 测试HOME和SHELL

HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)

HOME环境变量 就是 cd ~ 这个命令

普通用户:

image.png

超级用户:

image.png

SHELL : 当前 Shell,它的值通常是/bin/bash

       我们在Linux操作系统当中所敲的各种命令,实际上需要由命令行解释器进行解释,而在Linux当中有许多种命令行解释器(例如bash、sh),我们可以通过查看环境变量SHELL来知道自己当前所用的命令行解释器的种类

image.png

每一个环境变量都有自己特定的功能

8.7 通过系统调用获取环境变量

有两种方法:putenv 和 getenv,putenv 后面讲解,这里使用的是 getenv

man 查看一下

man 3 getenv

image.png

测试代码

USER:标识当前使用的 Linux用户

#include<stdio.h>    #include<stdlib.h>    intmain()    
{    
char*who=getenv("USER");    
printf("%s\n", who);                                                                                                                                
return0;    
}    

运行结果

image.png

8.8 环境变量通常是具有全局属性的

我们可以随便定义一个环境变量,比如

image.png

但是这个环境变量叫做本地环境变量,它是一个局部变量,在 env 全部环境变量里面查找是没有的

image.png

export: 设置一个新的环境变量,可以使用这个指令设置新的环境变量,再次查找就已经在 env 里面有了

[fy@VM-4-14-centos d2]$ export aaa

image.png

下面进行代码测试

#include<stdio.h>    #include<stdlib.h>    intmain()    
{    
char*myval=getenv("myval");    
if(myval==NULL)//getenv 查询为没有返回 NULL   {    
printf("myval no found\n");    
return1;    
   }    
printf("%s\n", myval);                                                                                                                                                 
return0;    
}    

没有设置环境变量 myval 之前,进行运行

image.png

定义一个新的本地环境变量 myval,并将 myval 设置成一个新的环境变量

image.png

再次运行程序

image.png

结果说明了:环境变量是可以被子进程继承下去

       bash 是一个系统进程,mytest 运行后也是一个进程,这个进程是 bash 的一个子进程,子进程能找到并打印环境变量 mytest,说明了子进程可以集成环境变量,子进程的环境变量是从 bash 来的,所以说环境变量具有全局属性

环境变量具有全局属性,根本原因是环境变量是可以被子进程继承下去

环境变量为什么要被子进程继承下去?

为了适应不同的场景,让 bash 帮找指令路径,进行身份验证

上面的 myval 没有设置成环境变量,当它只是一个本地变量时,它只会在当前进程 bash 内有效,它无法被子进程继承,所以它就是一个局部变量

----------------我是分割线---------------

  • unset: 清除环境变量
  • set: 显示本地定义的shell变量和环境变量

定义一个本地变量 yourval,不设置成环境变量

image.png

使用命令 set,里面会显示所有的环境变量并且包括本地变量

image.png

grep 查一下 yourval

image.png

如果这个环境变量不想要,使用命令 unset,再次查找这个环境变量或本地变量已经没有了

image.png

8.9 命令行参数

你是否知道 main 函数有参数吗?

答案是:有,而且是三个,只是我们平时基本不用它们,所以一般情况下都没有写出来

main 函数的三个参数为:int argc,char* argv[],char* env[]

main 函数也是函数,也是被调用的,这些参数一般是系统或父进程传的

这里我们先测试前面两个参数: int argc,char* argv[]

测试代码:

#include<stdio.h>    intmain(intargc, char*argv[])    
{    
inti=0;    
for(i=0; i<argc; ++i)    
    {    
printf("argv:[%d] -> %s\n", i, argv[i]);                                                                                                                           
    }    
return0;    
}    

运行结果,指针数组的 0 下标指向的就是 ./mytest

image.png

那再给它增加一些参数(程序后面是可以带参数的)

image.png

再给它增加一些参数,我们传的参数越多,它的 argv指针数组就越大

image.png

先不急解释上面的,我们先来看看一个经常使用的命令 ls

image.png

我们都知道命令后面是可以带选项的,ls 就是程序名,后面的 -a -b -l...是这个程序的选项,后面的选项参数有多少,char *argv[] 这个数组就有多大,argc 传的就是数组的大小

       比如:“ls -a -b -c -d -e”,命令行解析会把这个长的字符串拆分成一个个子字符串:"ls" "-a" "-b" "-c" "-d" "-e",这些子字符串就存在指针数组 char *arvg[] 里面,"ls" "-a" "-b" "-c" "-d" "-e" 共有 6个,所以 int argc 的大小就为 6

image.png

     一个命令就被解析成这样,这些工作一般是系统和 shell 做的,argc 代表你的命令行一共有多少个子字符串,argv 就是一张映射表,把每个子字符串一一映射在 argv 里面

为什么要解析成这样子?

为了执行不同的功能,比如“ls -a”,它就执行 -a 的功能,“ls -a -b”它就执行 -a -b 的功能,这就是命令行参数最大的意义

上面的 mytest 也是如此

接下来测试第三个参数 char* env[],它是用于获取环境变量的,它也是一个指针数组,以 NULL 结尾,与第二个参数一致

测试代码:

#include<stdio.h>    intmain(intargc, char*argv[], char*env[])    
  {    
inti=0;    
//env 也是以 NULL 结尾,NULL 就是 0    for(i=0; env[i]; ++i)    
      {                                                                                                                                                                    
printf("env:[%d] -> %s\n", i, env[i]);    
      }    
return0;    
  }    

运行结果,说明 char *env[] 就是用于获取环境变量的,这也说明我们写的程序为什么能够获取到环境变量

image.png

8.10 第三方变量 environ 获取环境变量

除了使用 main 函数的第三个参数和 getenv 来获取环境变量以外,我们还可以通过第三方变量 environ 来获取

man 查看 environ,它是一个二级指针,它其实指向的是 char *env[]

image.png

测试代码:

#include<stdio.h>    #include<unistd.h>    intmain()    
 {    
externchar**environ;                                                                                                                                             
inti=0;    
while(environ[i])    
     {    
printf("environ:[%d] -> %s\n", i, environ[i]);    
++i;    
     }    
return0;    
 }    

运行结果

image.png

注:libc 中定义的全局变量 environ 指向环境变量表,environ 没有包含在任何头文件中,所以在使用时要用 extern声明 总结一下:

在进程的上下文中,获取环境变量的三种方式为:

  1. getenv
  2. char *env[]
  1. extern char **environ

---------------我是分割线---------------

文章就到这里,下篇即将更新

相关文章
|
8月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
287 67
|
7月前
|
NoSQL Linux 编译器
GDB符号表概念和在Linux下获取符号表的方法
通过掌握这些关于GDB符号表的知识,你可以更好地管理和理解你的程序,希望这些知识可以帮助你更有效地进行调试工作。
313 16
|
7月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
204 16
|
7月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
141 20
|
6月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
125 0
|
6月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
187 0
|
6月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
127 0
|
6月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
165 0
|
9月前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
332 4
|
9月前
|
Linux 数据库 Perl
【YashanDB 知识库】如何避免 yasdb 进程被 Linux OOM Killer 杀掉
本文来自YashanDB官网,探讨Linux系统中OOM Killer对数据库服务器的影响及解决方法。当内存接近耗尽时,OOM Killer会杀死占用最多内存的进程,这可能导致数据库主进程被误杀。为避免此问题,可采取两种方法:一是在OS层面关闭OOM Killer,通过修改`/etc/sysctl.conf`文件并重启生效;二是豁免数据库进程,由数据库实例用户借助`sudo`权限调整`oom_score_adj`值。这些措施有助于保护数据库进程免受系统内存管理机制的影响。