• Linux 优先级 环境变量 命令行参数


    进程优先级

    概念:CPU分配资源的先后顺序,就是计算机中优先级的提现。优先级高的进程优先受到CPU的调度。以此CPU可以根据优先级更好的进行资源的分配。

    为什么会有优先级?

    优先级出现的本质原因是计算机中资源是有限的,每个进程都需要受到CPU的调度,操作系统需要根据计算机的运行状态对一些进程进行优先调用,所以优先级应运而生。

    优先级信息存储再在哪?

    优先级信息存储在PCB中。

    查看系统进程信息

    格式:ps -al
    功能:显示系统当前进程的部分信息
    在这里插入图片描述

    接下来我们一一对这些信息进行介绍:
       ( 1 ) (1) (1)UID
    全称:User Identification 用户身份证明

    UID表明了当前进程执行者的编号。我们知道进程=程序+内核对应的数据结构。在Linux中,我们查看某个进程的拥有者或者所属组时,其显示的都是具体的用户名。但是在Linux中其实这些用户名对应了一个个的编号。拿现实世界举例,UID就是身份证编号,其具有唯一性,而用户名就是姓名。

       ( 2 ) (2) (2)PID
    全称:Process Identification 进程表示符

    PID是每个进程独有的编号,用于区别计算机中的不同进程。
       ( 3 ) (3) (3)PPID
    PPID为当前进程父进程的编号。

       ( 4 ) (4) (4)NI
    NI是计算机中的进程修正数据,计算机中可以通过修改NI来间接修改优先级数据PRI

       ( 5 ) (5) (5)PRI
    PRI表明了进程优先级,PRI越小,其优先级越高。

    优先级的更改

    对于优先级的修改有多种方式,这里我们只讲一种:

       ( 1 ) (1) (1)top命令修改进程优先级
    前面我们介绍了优先级修正数据NI,我们一般都是使用NI来间接修改当前进程的优先级。
    公式:
    PIR(new)=PIR(old)+NI
    PIR(old)默认为80,所以每次我们只需要修改NI的数值,就可以直接修改当前进程的优先级。这也是为什么NI叫优先级修正数据的一个原因。

    注:NI的数值也可以称作nice值。
    nice值取值范围:-19-20

    接下来我们通过top命令对当前进程的PRI优先级进行一次修改:
    在这里插入图片描述

    修改过程如下:
    (1)输入top命令
    (2)输入进程PID
    (3)输入nice
    在这里插入图片描述

    但是,为什么nice需要设置一个范围呢?
    首先,我们需要知道,操作系统的存在是为了计算机资源能够受到更好的分配。所以说操作系统设置nice值一定是符合当前计算机运行状态的。
    如果扩大nice值范围,就会出现一个问题。
    一旦多个进程的优先级非常高,这时就可能导致一些优先级低的进程长时间不被CPU进行调度,这样就可能出现进程"饥饿问题"
    而操作系统需要较为均衡的让每个进程享受到CPU资源,所以人为不能进行过大的干预。

    事实上,在计算机中存在40个运行队列,正好对应nice值具有40个数值,因此CPU可以从高优先级的队列开始调度,依次顺下。

    扩充一些概念:
    竞争性:系统的进程很多,进程优先级就是不同进程之间竞争性的体现。
    独立性:进程与进程之间是独立的,互不影响的。
    并行:多个进程同时在不同的CPU上运行,也就是多进程同时运行
    并发:在单CPU中,在一段时间内,通过进程切换操作,使得多个进程都得以被CPU调度达到推进。

    环境变量

    前面我们提了一个概念:在Linux中,一切皆文件。
    命令,程序,工具的本质都是一个可以执行的文件
    我们平常写的test可执行程序也是一个文件,那么这个文件是否可以看作是一个命令呢?
    答案是对的,可以将其看作是一个命令。
    问题又来了,那为什么我们需要自己写的test命令,需要./test才能运行呢,而系统的命令ls,可以直接使用。

    为什么系统的命令不需要带路径呢?

    原因:因为环境变量

    接下来我们正式开始介绍部分环境变量:
    那么环境变量的本质是什么?

    环境变量也是一种变量:=变量名+变量内容
    定义变量不仅仅是语言的任务,语言上面定义变量本质是在内存中开辟空间(有编号/名字),环境变量本质是操作系统在内存/磁盘中开辟的空间,用来保存系统相关的数据,环境变量和语言中定义的变量其实没有太多的区别,只不过环境变量存储的是系统的一些数据,而语言定义的变量存储的一般是一些具体的数值,两者都是变量名+变量内容,只不过环境变量是操作系统自动替我们执行的

       ( 1 ) (1) (1)PATH
    执行系统的命令其实也需要带路径,但是这一工作操作系统替我们干了。在环境变量PATH中存储了很多组不同的路径,操作系统会从前往后进行路径的匹配,当匹配成功时就执行该命令。所以说我们在使用系统命令的时候不用带路径,因为操作系统承担了这一工作。

    像如gccgdb可以直接使用,可以直接连接库文件…都是因为环境变量的存在,所以可以直接进行检索。

    在这里插入图片描述

       ( 2 ) (2) (2)HOME
    每个用户的HOME环境变量都是不一样的

    格式:echo $环境变量名
    功能:查看环境变量

    注:
    安装软件到系统中,其实本质就是将软件拷贝到系统环境变量中的特定路径下。

    格式:export 环境变量名= 路径
    功能:环境变量内原有路径被清空,并被赋予进新的路径

    通过export指令我们可以使得自己的命令也不需要带路径,并且还可以验证系统命令会自动到PAHT环境变量中匹配路径

    生成一个proc可执行程序,源代码如下

    
    int main()
    {
    	cout<<"验证成功"<<endl;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    将该可执行程序的路径通过export导入PATH环境变量
    在这里插入图片描述

    注:导入的环境变量都是单次登录有效的,因为没有修改配置文件。

    格式:export 环境变量名= $环境变量名:路径
    功能:在环境变量原有路径的基础上追加一条新的路径

    环境变量的全局属性

    2.对于环境变量,我们需要知道环境变量具有全局性。
    这里的全局性和继承该如何理解呢?

    子进程会继承父进程的环境变量。

    接着我们通过一棵多叉树进行解释。
    在这里插入图片描述
    我们知道在Linux中,都是bash为我们和操作系统进行交互,用户在登陆的时候,bash会自动从~/.bashrc~/.bash_profile这两个配置文件中把环境变量读入了自己的环境变量列表中,父进程会将环境变量参数传递给运行的子进程,这样子进程就继承了父进程的环境变量,这就使得每一个子进程都间接或直接继承了bash的环境变量,所以说环境变量具有全局性,就像这棵多叉树一样,影响了整个用户系统。

    所以我们使用gcc,g++这些命令的时候都够不带选项,直接链接一些库,还是因为其继承了bash的环境变量,所以系统会自动替我们查找。

    关于子进程会继承父进程的环境变量,在文章的末尾我们会进行代码上的验证。

    本地变量

    格式:env
    功能:查看当前系统的环境变量

    系统上还存在一种变量,只在本次登录有效,称为本地变量
    我们自己创建的变量基本都是本地变量。

    注意:本地变量不具有继承属性。

    在这里插入图片描述
    在这里插入图片描述

    格式:set
    功能:显示本地变量和环境变量

    格式:export 本地变量
    功能:将本地变量转成环境变量
    注:但是这个本地变量因为没有写入配置文件里,即使导入变成了环境变量,关掉xshell以后一样会被清除。

    格式:unset 本地变量/环境变量
    功能:取消本地定义的本地变量或者环境变量

    命令行参数

    在了解什么是命令行参数之前,我们需要重新看向main函数。
    main函数内其实也是可以传递参数的,这里我们先介绍其中的两个参数。

    参数一:char *argv[]
    作用:argv是一个char类型的动态指针数组。argv的长度由argc决定。
    参数二:int argc
    作用:决定argv的长度

    实际上,我们在命令行上敲的命令和后缀其实都是传递给了argv这个指针数组
    lsls -a,以及我们自己写的可执行程序./proc./proc -a等等,如果我们的命令不带后缀选项,那么argv数组就只有源程序一个元素,argc个数就是我们传递的参数个数,也就是argv的元素个数。
    对此我们进行验证:

    int main(int argc,char*argv[])
      {
        for(int i=0;argv[i];i++)
          cout<<argv[i]<<endl;
      
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    为了更好的理解,我们通过一个图像来进一步理解argv这个字符指针数组。
    在这里插入图片描述

    为什么要使用命令行参数呢?

    因为命令行参数的存在,我们可以通过if else语句进行筛选,从而实现一个命令的不同子功能,我们都知道一个命令具有很多的后缀选项,如mkdir -pls -a等等,其实这些命令选项底层的实现使用的就是命令行参数。
    因此我们可以通过代码来定制我们的命令后缀选项。

    int main(int argc,char*argv[])
    {
      if(argc!=2)
      {
        cout<<"你需要传递一个参数进来"<<endl;      
        return 0 ;      
      }      
             
             
          if(strcmp(argv[1],"a")==0)                                                       
            cout<<"参数传递正确"<<endl;      
          else      
            cout<<"参数传递错误"<<endl; 
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    获取环境变量

       ( 1 ) (1) (1)env数组
    前面我们通过main函数的前两个参数引出了命令行参数的概念,接着我们介绍main函数的第三个参数。
    main函数除了可以传递命令行参数以外,还可以传递环境变量。
    参数三:char* env[]
    功能:接收环境变量参数
    当父进程创建子进程的时候,子进程在运行代码的时候,父进程会将环境变量参数传递给子进程的env数组
    这个想必也非常好理解,因此通过第三个参数我们可以打印出进程当前的环境变量。

     #include    
      using namespace std;    
          
          
    E>int main(char *env[])    
      {    
        for(int i=0;env[i];i++)    
          cout<<env[i]<<endl;                                                              
      } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述
    我们依旧是通过一个图来加深对env数组的印理解
    在这里插入图片描述
    为何命令行参数中argv数组的元素个数等于argc个,而环境变量没有具体的个数参数。

    首先,我们需要知道二者的区别,命令行参数是用户填入的,而环境变量是系统填入的,并不需要人为控制,因此具体的个数没有太大的意义。

       ( 2 ) (2) (2)environ指针
    environ是一个系统提供的第三方变量指针,其是一个二级指针,这个二级指针指向了env数组的首元素,在编译的时候系统会自动让其指向环境变量的位置,因此可以通过environ指针来获取环境变量。
    在这里插入图片描述

    代码如下:

    
    #include    
    #include    
        
    int main()    
    {    
      extern char** environ;                                                                                                                  
      for(int i = 0;environ[i];i++)    
      {    
        printf("%s\n",environ[i]);    
      }
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述
       ( 3 ) (3) (3)env命令

    格式:env
    功能:获取环境变量

       ( 4 ) (4) (4)getenv函数

    头文件:#include
    格式:getenv(环境变量名)
    功能:getenv函数会返回对应环境变量的字符串。

    验证环境变量具有全局属性

    首先,我们需要知道在命令行上启动的进程,父进程大都是是bash,除此之外,系统内还有一些内置命令如export等等都是由父进程自己执行的。

    在这里插入图片描述

    关于环境变量与继承(重要)

    fork中我们谈到了继承关系,需要注意只有fork创建的子进程才会继承父进程的代码和数据,以父进程的PCB,进程地址空间和页表(在下一个博客会讲到)为模板构建自己的PCB,进程地址空间和页表。普通的父进程和子进程之间不具有这种继承属性。
    而对于环境变量的继承性是所有父子进程之间都具有这种继承的属性,这里大家要分辨清楚,不要搞混了。

  • 相关阅读:
    行业追踪,2023-09-11
    atof函数的实现
    智能算法与机器学习结合案例:KNN结合BBA算法,100%分类率
    2022年全国大学生数学建模竞赛E题目-小批量物料生产安排详解+思路+Python代码时序预测模型(一)
    【数据结构初阶】线性表——单链表(手撕单链表)
    【Ingress】
    Python与Java的12点区别介绍
    电子学会2023年6月青少年软件编程(图形化)等级考试试卷(四级)真题,含答案解析
    [移动通讯]【无线感知-P2】[特征,算法,数据集】
    Java随笔-Socket
  • 原文地址:https://blog.csdn.net/weixin_59112191/article/details/125267795