【Linux取经路】解析环境变量,提升系统控制力

在这里插入图片描述

文章目录

  • 一、进程优先级
    • 1.1 什么是优先级?
    • 1.2 为什么会有优先级?
    • 1.3 小结
  • 二、Linux系统中的优先级
    • 2.1 查看进程优先级
    • 2.2 PRI and NI
    • 2.3 修改进程优先级
    • 2.4 进程优先级的实现原理
    • 2.5 一些名词解释
  • 三、环境变量
    • 3.1 基本概念
    • 3.2 PATH:Linux系统中的指令搜索路径
    • 3.3 HOME
    • 3.4 USER
  • 四、命令行参数
    • 4.1 命令行参数的作用
    • 4.2 main函数的第三个参数
    • 4.3 环境变量可继承的验证
  • 五、本地变量与内建命令
    • 5.1 在bash命令行输入的指令并不一定都要创建子进程
  • 六、结语

一、进程优先级

1.1 什么是优先级?

优先级决定了资源分配的先后顺序,即谁先访问,谁后访问。要注意区分优先级和权限的概念,权限决定了能不能做,而优先级是在已经确定可以做的基础上,去决定谁先谁后的问题。

1.2 为什么会有优先级?

因为在系统中可能存在多个进程,但是只有一个 CPU,这就注定了所有的进程是需要去竞争 CPU 资源,操作系统必须保证所有的进程良性竞争,即让每个进程都能使用到 CPU 资源。这就像去食堂买饭,如果大家不排队都去抢饭,那么弱小的人永远也抢不到饭。而排队的顺序就需要通过优先级来确定,优先级高的排在前面,优先级低的排在后面。如果因为优先级设计不合理(调度算法设计不合理)导致我们的进程长时间得不到 CPU 资源,该进程的代码长时间无法得到推进,就会产生该进程的饥饿问题,在用户看来就是应用卡死。

1.3 小结

  • CPU 资源分配的先后顺序,就是指进程的优先权。

  • 优先级高的进程有优先执行权利。配置进程优先级对多任务环境的 Linux 很有用,可能会改善系统性能(注意:不要随意的修改进程优先级,只有调度器能够最公平的帮我们调度进程)。

  • 还可以把进程运行到指定 CPU 上,这样一来,把不重要的进程安排到某个 CPU,可以大大改善系统整体性能。

二、Linux系统中的优先级

2.1 查看进程优先级

//process.c
int main()                                                      
{                                                               while(1)                                                    {                                                           printf("I am a process, PID:%d, PPID:%d\n",getpid(),getppid());    sleep(1);                                               }                                                           return 0;                                                                                                                                                                                 
}
//通过ps -al 指令可以查看进程的优先级ps -al | head -1 ; ps -al | grep process

在这里插入图片描述

  • UID:代表执行者的身份。

  • PID:代表这个进程的代号。

  • PPID:代表这个进程是由哪个进程发展衍生而来的,即父进程的代号。

  • PRI:代表这个进程可被执行的优先级,其值越小越早被执行,是 task_struct 结构体对象中的一个成员。

  • NI:代表这个进程的 nice 值,是进程优先级的修正数据。

2.2 PRI and NI

  • PRI 即进程的优先级,或者通俗点说就是程序被 CPU 执行的先后顺序,此值越小,进程的优先级别越高。

  • NI 就是我们呢常说的 nice 值,表示进程可被执行的优先级的修正数值。

  • PRI 值越小越快被执行,那么加入 nice 值后,将会使得 PRI(new) = PRI(old) + nice。

  • 当 nice 值为负数的时候,那么该程序的优先级值将会变小,即优先级会变高,其会越快被 CPU 执行。

  • 所以调整进程优先级,在 Linux 下就是调整进程的 nice 值。

  • nice 值的取值范围是[-20,19],一共40个级别。

2.3 修改进程优先级

普通用户是无法修改进程优先级的,因此要修改进程优先级必须切换成 root 用户。

top
//进入top后按“r”->输入进程PID->输入nice值

在这里插入图片描述

小Tips:PRI(new) = PRI(old) + nice中的 PRI(old) 永远都是从80开始。

2.4 进程优先级的实现原理

在这里插入图片描述
修改进程的优先级,本质上就是修改进程 PCB 对象所在的队列,将进程的 PCB 对象链入到修改后优先级对应的数组下标处,不同的下标就对应不同的优先级队列。

2.5 一些名词解释

  • 竞争性:系统进程数目众多,而 CPU 资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。

  • 独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。

  • 并行:多个进程在多个 CPU 下分别同时运行,这称之为并行。

  • 并发:多个进程在一个 CPU 下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

并发情况下,操作系统会根据每个进程的时间片去进行进程切换,当前正在被 CPU 调度的进程在它的时间片结束还没有执行结束,会被操作系统从 CPU 上拿下来,到上图中的 waiting 数组里面去继续排队,等待 CPU 的下一次调度,我们把这种过程叫做进程基于时间片轮转的调度算法。那 CPU 在下次调度该进程的时候,是如何直到从那里继续执行呢?答案是通过程序计数器(也叫PC指针),是 CPU 中的一个寄存器,一般是 epi,用于存储下一条将要执行的指令的内存地址,这样以来 CPU 下一次再调度该进程的时候就知道该从哪里继续执行了。

小Tips:CPU 中的寄存器有很多种,例如:通用寄存器eax、ebx、ecx、edx;和栈帧有关的ebp、esp、eip;和状态有关的status。寄存器也有对数据保存的能力,计算机在运行时一些重要的数据一定要保存在 CPU 内部,即寄存器中,因为寄存器离 CPU 很近存储效率高,所以 CPU 内的寄存器保存的是进程相关的数据,可以随时被 CPU 访问或者修改,这种和进程有关的数据也被叫做进程的上下文。进程在从 CPU 上离开的时候。要将自己的上下文数据保存好,甚至带走,保存好的目的是为了未来恢复。进程在被切换的时候,要执行两步操作,即保存上下文和恢复上下文,进程的上文数据量并不大,一般可以直接保存到进程的 PCB 对象中,当 CPU 再次调度该进程的时候,将这些上下文数据再恢复到寄存器里面即可。

三、环境变量

3.1 基本概念

  • 环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。

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

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

在这里插入图片描述
上图是 Windows 系统下的环境变量,本质上就是一组 key-value ,接下来将以Linux中的一些现象来演示常见的环境变量。

3.2 PATH:Linux系统中的指令搜索路径

我们平时在 bash 命令行中执行自己写的可执行程序时需要加 ./,表示当前目录下的可执行程序,告诉操作系统执行的时候在该目录下查找,指令本质上也是可执行程序,但是我们在执行指令的时候却从来没有加任何路径,那操作系统是如何直到指令在哪个目录呢?之前我们提到过,所有的指令都在/usr/bin/目录下,而我们自己写的可执行程序是在我们自己当前的工作目录下。都是目录怎么还会有区别呢?因为 Linux 操作系统会为我们提供一个环境变量 PATH,它是 Linux 操作系统给我们提供的指令搜索路径,这个环境变量是自从我们开机登录上 Xshell 就存在的,可以通过下面这条指令来查看 PATH 变量的值。

echo $PATH

在这里插入图片描述
PATH 变量值是用冒号分隔开的一些路径,这些路径就是我们平时执行指令时,系统去查找指令的路径,这就是为什么执行指令的时候不需要加 ./, 因为系统会自动到 PATH 对应的路径下去挨个搜索,这些指令都在/usr/bin/目录下,并且/usr/bin/目录也是 PATH 的变量值,所以指令最终一定会被找到,而我们自己写的可执行程序一般都是在当前的工作目录下,这个目录并不是 PATH 变量的值,如果不加 ./ 操作系统会自动到 PATH 对应的所有路径下挨个去搜索,最终都没有找到该可执行程序,也就无法执行。可以通过下面这条指令将当前的工作目录添加到环境变量里。

PATH=$PATH:/home/wcy/linux-s/lesson13
///home/wcy/linux-s/lesson13是当前工作目录
//只用=是覆盖写的意思,会把原本的PATH 覆盖掉

在这里插入图片描述
再去查看 PATH 的值,此时我们当前的工作目录也被添加了进去,此时在该目录下的可执行程序在执行的时候就可以不加 ./ 了。

小Tips:我们上面修改的环境变量是一种内存级的环境变量,保存在 shell 中,每次登陆 shell 会从系统的一些配置文件中将环境变量加载到 shell ,所以我们上面这种修改并不会影响到系统的配置文件,因此每次重启登陆环境变量就可以恢复如初。

3.3 HOME

我们每次登陆 shell 都默认处在家目录下,这是因为我们每次登陆的时候,shell 会识别到当前登陆的用户,自动帮我们填充 $HOME 环境变量,登陆的时候 shell 会为我们分配命令行解释器 bash,bash 本质上也是一个可执行程序,它会帮我们执行 cd $HOME 指令,这就是为什么我们每次登陆,都默认在家目录下。

小Tips:我们可以通过 env 指令查看当前 bash 从操作系统中继承下来的所有环境变量。

在这里插入图片描述
除了使用 env 指令,我们还可以通过 getenv 这个系统调用接口来获取某个环境变量的值。

3.4 USER

通过 USER 这个环境变量可以实现权限的认证,不同的用户登录 shell,它的 USER 是自己的用户名。

#include <stdio.h>
#include <stdlib.h>int main()
{printf("USER:%s\n",getenv("USER"));return 0;
}

同一份代码不同的用户去执行会得到不同的结果。

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
int main()    
{    char user[32];    strcpy(user, getenv("USER"));    if(strcmp("root",user) == 0)    {    printf("root用户,不受权限约束\n");    }    else    {    printf("普通用户,受权限约束\n");    }    printf("USER:%s\n",getenv("USER"));    return 0;                                                                         
}    

在这里插入图片描述
正式因为 USER 这个环境变量的存在,操作系统就具备了识别当前登录用户的能力,进而可以和文件对应的拥有者、所属组以及对应的权限做对比,一次来判断当前用户是否具有某项权限。

四、命令行参数

C/C++ 的 main 函数是可以传参的,这两个参数就叫做命令行参数,如下所示:

int main(int argc, char* argv[])
{return 0;
}

argv 是一个指针数组,里面保存的是字符串地址,这个数组有 argc 个元素。

int main(int argc, char* argv[])    
{    int i = 0;    for(; i < argc; i++)    {    printf("argv[%d]->%s\n",i, argv[i]);    }    return 0;                                                                                                                                          
} 

在这里插入图片描述
main 函数做i为函数也是可以被调用的,它也有参数,调用 main 函数的时候可以传参。我们在 bash 命令行输入的:./mycode -a -b -c会被 bash 当成一个字符串,它会把这整个字符串以空格作为分隔符,分成一个个单独的字符串,然后将它们的地址存入到 argv 数组中。

小Tips:假设 argc == N,即有 N 个命令行参数,那么 argv[N] 会默认设置成 NULL

4.1 命令行参数的作用

#include <stdio.h>int main(int argc, char* argv[])    
{    if(argc != 2)    {    printf("./mycode [-a|-b|-c|-d]\n");    return 0;    }    if(strcmp(argv[1], "-a") == 0)    {    printf("执行功能1\n");    }    else if(strcmp(argv[1], "-b") == 0)    {    printf("执行功能2\n");    }    else if(strcmp(argv[1], "-c") == 0)    {    printf("执行功能3\n");    }    else if(strcmp(argv[1], "-d") == 0)    {    printf("执行功能4\n");    }                                                                                                                                                  else     {    printf("没有该选项!\n");    }    return 0;    
}    

在这里插入图片描述
命令行参数有一个重要的作用,它可以为指令、工具、软件等提供命令行选项的支持。

4.2 main函数的第三个参数

除了上面提到的 argc 和 argv 两个参数,main 函数还有第三个参数 env,它也是一个指针数组,存放的是该进程的环境变量。

#include <stdio.h>
int main(int argc, char* argv[], char* env[])    {    int i = 0;    for(;env[i]; i++)    {    printf("env[%d]->%s\n", i, env[i]);    }    return 0;                                                                                                                                        } 

在这里插入图片描述
总结:我们平时写的 C/C++ 代码会有两张核心向量表,一张叫命令行参数表,另一张叫环境变量表。我们平时执行的指令,自己写的可执行程序都是 bash 的子进程,bash 本身在启动的时候,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程交给我的环境变量。这就是环境变量具有全局特性的本质。

4.3 环境变量可继承的验证

通过下面这条指令在 bash 的上下文数据中添加一个我们自己的环境变量,通过查看子进程中是否有该环境变量来验证环境变量可以被子进程继承。

export MY_VALUE=12345678

在这里插入图片描述
下面执行子进程 ./mycode,可以发现它里面也有 MY_VALUE 这个环境变量,说明子进程 mycode 继承了父进程 bash 的环境变量。

在这里插入图片描述
正是因为子进程可以继承父进程的环境变量,所以我们在 bash 输入的所有指令都要遵守权限,因为输入的所有指令都可以看做是 bash 的子进程,都继承了 bash 的环境变量。通过下面这条指令可以删除环境变量。

unset MY_VALUE

五、本地变量与内建命令

本地变量就是在命令行中直接定义的变量。

在这里插入图片描述
可以通过 set 命令查到系统当中的所有环境变量和本地变量。其中本地变量是不会被子进程继承的,只会在本 bash 内有效。可以通过 export 指令将一个本地变量变成环境变量。

export MYVALUE
//MYVALUE本来是一个本地变量
//执行完这条指令后MYVALUE就会变成一个环境变量

5.1 在bash命令行输入的指令并不一定都要创建子进程

如上图所示,我们可以通过 echo 指令打印出本地变量,之前说过 echo 作为指令,本质上也是一个可执行程序,既然是可执行程序,那就会创建进程,但是我们又说了子进程是无法继承父进程的本地变量,那为什么 echo 可以打印出父进程 bash 的本地变量呢?原因是:并不是所有的指令都会创建子进程。指令可以分为以下两类:

  • 常规命令:通过创建子进程完成的。

  • 内建命令:bash 不创建子进程,而是由自己亲自执行,类似于 bash 调用了自己写的,或者系统提供的函数。

而 echo 就是一个内建命令,执行 echo 命令的时候并不会创建子进程,与此类似的还有 cd 命令,它也是一个内建命令,通过调用 chdir 系统接口可以改变当前进程的工作目录。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>                                                                            int main(int argc, char* argv[], char* env[])    
{    sleep(30);    printf("change begin\n");    if(argc == 2)    {    chdir(argv[1]);    }    printf("change end\n");    sleep(30);    return 0;    
}   

在这里插入图片描述
在 bash 命令行输入 cd 命令的时候,bash 并不会创建子进程,而是去判断命令行参数是否为 cd,如果是就直接去调用 chdir 系统接口切换工作目录。

小Tips:除了上面提到的两种通过代码获取环境变量的方法(命令行第三个参数、getenv系统接口)外,还可以通过第三方变量environ获取,libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。

#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;
}

六、结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,春人的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是春人前进的动力!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/97948.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s 常见面试题

前段时间在这个视频中分享了 https://github.com/bregman-arie/devops-exercises 这个知识仓库。 这次继续分享里面的内容&#xff0c;本次主要以 k8s 相关的问题为主。 k8s 是什么&#xff0c;为什么企业选择使用它 k8s 是一个开源应用&#xff0c;给用户提供了管理、部署、扩…

Learning to Super-resolve Dynamic Scenes for Neuromorphic Spike Camera论文笔记

摘要 脉冲相机使用了“integrate and fire”机制来生成连续的脉冲流&#xff0c;以极高的时间分辨率来记录动态光照强度。但是极高的时间分辨率导致了受限的空间分辨率&#xff0c;致使重建出的图像无法很好保留原始场景的细节。为了解决这个问题&#xff0c;这篇文章提出了Sp…

idea2023 springboot2.7.5+mybatisplus3.5.2+jsp 初学单表增删改查

创建项目 修改pom.xml 为2.7.5 引入mybatisplus 2.1 修改pom.xml <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><!--mysq…

【STM32 学习】电源解析(VCC、VDD、VREF+、VBAT)

VCC电源电压GND电源供电负电压&#xff08;通常接地&#xff09;VDD模块工作正电压VSS模块工作负电压VREFADC参考正电压VREF-ADC参考负电压VBAT电池或其他电源供电VDDA模拟供电正电压VSSA模拟供电负电压 一、VCC&#xff08;供电电压&#xff09; VCC是指芯片的电源电压&#…

MNIST手写数字数据集+7000张图片下载

MNIST手写数字图像数据集是一个经典的用于图像分类任务的数据集&#xff0c;其中包含了大量的手写数字图像样本 数据集点击下载&#xff1a; MNIST手写数字数据集7000张图片.rar

函数栈帧理解

本文是从汇编角度来展示的函数调用&#xff0c;而且是在vs2013下根据调试展开的探究&#xff0c;其它平台在一些指令上会有点不同&#xff0c;指令不多&#xff0c;简单记忆一下即可&#xff0c;在我前些年的学习中&#xff0c;学的这几句汇编指令对我调试找错误起了不小的作用…

【令牌桶算法与漏桶算法】

&#x1f4a7; 令牌桶算法与漏桶算法 \color{#FF1493}{令牌桶算法与漏桶算法} 令牌桶算法与漏桶算法&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算法》专…

【前端|JS实战第1篇】使用JS来实现属于自己的贪吃蛇游戏!

前言 贪吃蛇游戏是经典的小游戏&#xff0c;也是学习前端JS的一个很好的练习项目。在本教程中&#xff0c;我们将使用 JavaScript 来逐步构建一个贪吃蛇游戏。我们会从创建游戏区域开始&#xff0c;逐步添加蛇的移动、食物的生成以及游戏逻辑等功能。 &#x1f680; 作者简介&a…

韦东山-电子量产工具项目:业务系统

代码结构 所有代码都已通过测试跑通&#xff0c;其中代码结构如下&#xff1a; 一、include文件夹 1.1 common.h #ifndef _COMMON_H #define _COMMON_Htypedef struct Region {int iLeftUpX; //区域左上方的坐标int iLeftUpY; //区域左下方的坐标int iWidth; //区域宽…

java八股文面试[java基础]——String StringBuilder StringBuffer

String类型定义&#xff1a; final String 不可以继承 final char [] 不可以修改 String不可变的好处&#xff1a; hash值只需要算一次&#xff0c;当String作为map的key时&#xff0c; 不需要考虑hash改变 天然的线程安全 知识来源&#xff1a; 【基础】String、StringB…

Python web实战之细说 Django 的单元测试

关键词&#xff1a; Python Web 开发、Django、单元测试、测试驱动开发、TDD、测试框架、持续集成、自动化测试 大家好&#xff0c;今天&#xff0c;我将带领大家进入 Python Web 开发的新世界&#xff0c;深入探讨 Django 的单元测试。通过本文的实战案例和详细讲解&#xff…

ubuntu安装Microsoft Edge并设置为中文

1、下载 edge.deb 版本并安装 sudo dpkg -i microsoft-edg.deb 2. 设置默认中文显示 如果是通过.deb方式安装的&#xff1a; 打开默认安装路径下的microsoft-edge-dev文件&#xff0c;在文件最开头加上: export LANGUAGEZH-CN.UTF-8 &#xff0c;保存退出。 cd /opt/micr…

PHP8的字符串操作3-PHP8知识详解

今天继续分享字符串的操作&#xff0c;前面说到了字符串的去除空格和特殊字符&#xff0c;获取字符串的长度&#xff0c;截取字符串、检索字符串。 今天继续分享字符串的其他操作。如&#xff1a;替换字符串、分割和合成字符串。 5、替换字符串 替换字符串就是对指定字符串中…

【算法系列篇】滑动窗口

文章目录 前言什么是滑动窗口1.长度最小的子数组1.1 题目要求1.2 做题思路 1.3 Java代码实现2.无重复字符的最长子串2.1 题目要求2.2 做题思路2.3 Java代码实现 3.最大连续1的个数 III3.1 题目要求3.2 做题思路3.3 Java代码实现 4.将x减到0的最小操作数4.1 题目要求4.2 做题思路…

【仿写框架之仿写Tomact】四、封装HttpRequest对象(属性映射http请求报文)、HttpResponse对象(属性映射http响应报文)

文章目录 1、创建HttpRequest对象2、创建HttpResponse对象 1、创建HttpRequest对象 HttpRequest对象中的属性与HTTP协议中的内容对应&#xff0c;用于后序servlet从request中获取请求中的参数。 参照http请求报文&#xff1a; import java.io.BufferedReader; import java…

配置使用Gitee账号认证登录Grafana

三方社会化身份源 集成gitee第三方登录 第三方登录的原理 所谓第三方登录&#xff0c;实质就是 OAuth 授权。用户想要登录 A 网站&#xff0c;A 网站让用户提供第三方网站的数据&#xff0c;证明自己的身份。获取第三方网站的身份数据&#xff0c;就需要 OAuth 授权。 举例来…

ubuntu上使用osg3.2+osgearth2.9

一、介绍 在ubuntu上使用osgearth加载三维数字地球&#xff0c;首先要有osg和osgearth的库&#xff0c;这些可以直接使用apt-get下载安装&#xff0c;但是版本有些老&#xff0c;如果需要新版本的就需要自己编译。 #查看现有版本 sudo apt-cache madison openscenegraph #安装…

Python写一个创意五子棋游戏

前言 在本教程中&#xff0c;我们将使用Python写一个创意五子棋游戏 &#x1f4dd;个人主页→数据挖掘博主ZTLJQ的主页 个人推荐python学习系列&#xff1a; ☄️爬虫JS逆向系列专栏 - 爬虫逆向教学 ☄️python系列专栏 - 从零开始学python 首先 GomokuGame 类的构造函数 __ini…

小程序 CSS-in-JS 和原子化的另一种选择

小程序 CSS-in-JS 和原子化的另一种选择 小程序 CSS-in-JS 和原子化的另一种选择 介绍快速开始 pandacss 安装和配置 0. 安装和初始化 pandacss1. 配置 postcss2. 检查你的 panda.config.ts3. 修改 package.json 脚本4. 全局 css 注册 pandacss5. 配置的优化与别名 weapp-pand…

LeetCode 周赛上分之旅 #40 结合特征压缩的数位 DP 问题

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难度…