当前位置: 首页 > news >正文

Linux进程概念(中):进程优先级和环境变量

文章目录

    • 一、进程优先级
      • 优先级是什么?
      • 为什么需要优先级?
      • 怎么控制进程优先级?
        • 查看进程优先级
        • PRI and NI
        • PRI vs NI
        • 用top命令修改进程的nice
        • 用renice命令修改进程的nice值
    • 二、环境变量
      • 基本概念
      • 常见环境变量
      • 查看环境变量方法
      • 测试PATH
        • 方式一:将可执行程序拷贝到环境变量PATH的某一路径下。
        • 方式二:将可执行程序所在的目录导入环境变量PATH中
      • 测试HOME
      • 测试SHELL
      • 和环境变量相关的一些命令
      • 环境变量的组织方式
      • 通过代码获取环境变量
        • 方式一:命令行第三个参数
          • 命令行参数
        • 通过第三方变量environ获取
      • 通过系统调用获取特定环境变量
      • 环境变量通常是具有全局属性的
      • 本地变量 and 内建命令


一、进程优先级

优先级是什么?

优先级就是获取某种资源的先后顺序。
进程优先级就是进程获取CPU资源分配的先后顺序,进程获取CPU资源分配的先后顺序,就是指进程的优先权(priority),优先权高的进程有优先执行的权力。

为什么需要优先级?

主要原因是因为资源是有限的。
需要进程优先级的主要原因就是CPU资源是有限的

竞争性:因为CPU资源是有限的,而进程是多个的,所以进程之间是具有竞争属性的

操作系统为了高效完成任务,让进程良性竞争相关资源,,于是便有了优先级。

如果一个进程长时间得不到CPU资源,该进程的代码会长时间得不到推进,造成该进程的饥饿问题。存在该问题的操作系统是低效的。

怎么控制进程优先级?

查看进程优先级

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

ps -l

在这里插入图片描述
我们很容易注意到其中的几个重要信息,如下:

  • UID:代表执行者的身份
  • PID:代表这个进程的id
  • PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI:代表这个进程可被执行的优先级,其值越小越早被执行
  • NI:代表这个进程的nice值
PRI and NI
  • PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
  • 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
  • PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:
    PRI(new)=PRI(old)+nicePRI(new)=PRI(old)+nicePRI(new)=PRI(old)+nice
  • 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即优先级会变高,则其越快被执行
  • 因此,我们调整进程优先级,在Linux下,就是调整进程nice值
  • 但是,如果用户随意修改进程优先级,是不安全的。
  • 所以nice其取值范围是-20至19,一共40个级别

注意:在Linux操作系统当中,PRI(old)默认为80,即PRI = 80 + NI

PRI vs NI
  • 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化
  • 可以理解nice值是进程优先级修正的修正数据
用top命令修改进程的nice

top命令就相当于Windows中的任务管理器,它能够动态实时的显示系统当中进程的资源占用情况。
在这里插入图片描述
修改步骤:

  1. 进入top后按‘r’
  2. 输入需要修改进程的PID
  3. 输入nice值
用renice命令修改进程的nice值

使用renice命令,后面跟上更改后的nice值和进程的PID即可
在这里插入图片描述
注意: 若是想使用renice命令将NI值调为负值,也需要使用sudo命令提升权限。


二、环境变量

基本概念

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

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

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

常见环境变量

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

查看环境变量方法

可以通过echo命令来查看环境变量,如下:

echo$NAME //NAME为需要查看的环境变量名称

在这里插入图片描述

测试PATH

我们知道,我们平时使用的命令本质也就是一个一个的可执行程序,然而我们使用命令却不带./就可以执行,而我们自己生成的可执行程序必须要在前面加上./才能执行。
在这里插入图片描述
./的作用是什么?没错,就是告诉系统可执行程序的位置。

因为 Linux 默认不会在当前目录下寻找可执行程序,而 ./ 明确地告诉系统:“我要运行的程序就在当前目录下”

而命令无需./,系统是如何知道它的位置呢?
就是通过环境变量PATH来找到命令的,查看环境变量PATH我们可以看到如下内容:
在这里插入图片描述
可以看到环境变量PATH当中有多条路径,这些路径由冒号隔开,当你使用ls命令时,系统就会查看环境变量PATH,然后默认从左到右依次在各个路径当中进行查找。

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

当然是可以滴!

方式一:将可执行程序拷贝到环境变量PATH的某一路径下。
sudo cp proc /usr/bin

在这里插入图片描述

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

用export命令,可以将某个目录导入到环境变量PATH中:

export PATH=$PATH:/home/zhh/process_code

在这里插入图片描述
这样,我们无需./就可以执行程序了:
在这里插入图片描述

测试HOME

任何一个用户在运行系统登录时都有自己的主工作目录(家目录),环境变量HOME当中即保存的该用户的主工作目录。

普通用户:
在这里插入图片描述
超级用户root:
在这里插入图片描述

测试SHELL

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

而该命令行解释器实际上也是系统当中的一条命令,当这个命令运行起来变成进程后就可以为我们进行命令行解释。

和环境变量相关的一些命令

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

环境变量的组织方式

在这里插入图片描述
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串

通过代码获取环境变量

方式一:命令行第三个参数
命令行参数

你可能不知道,main函数其实是有参数的:
在这里插入图片描述
因为我们平时几乎用不上它们,所以一般情况下都没有写出来。

其实,这三个参数称为命令行参数
既然argv是一个字符数组指针,我们不妨打印看看内容:

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

在这里插入图片描述
原来,argv当中的第一个字符指针存储的是可执行程序的位置,其余字符指针存储的是所给的若干选项,最后一个字符指针为空。
原理很好理解,先初始化指针数组的每个指针为空,然后读取命令行字符串,遇上空格就换下一个字符指针读取,直到字符串读取完毕

在这里插入图片描述
而main函数的第一个参数argc代表的就是字符指针数组当中的有效元素个数。

argc和argv结合使用就可以根据你所给选项给出不同的提示语:

#include <stdio.h>                                                                                                                         
#include <string.h>
int main(int argc, char *argv[], char* envp[])
{if(argc > 1){if(strcmp(argv[1], "-a") == 0){printf("you used -a option...\n");}else if(strcmp(argv[1], "-b") == 0){printf("you used -b option...\n");}else{printf("you used unrecognizable option...\n");}}else{printf("you did not use any option...\n");}return 0;
}

运行结果:
在这里插入图片描述

其实,这就是我们平时使用的命名的选项的实现逻辑!

main函数的第三个参数envp接收的实际上就是环境变量表,我们可以通过main函数的第三个参数来获取系统的环境变量。

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

运行结果同样是和env指令是一样的,可以显示所有环境变量

通过第三方变量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;
}

运行结果也同样是和env指令是一样的

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

在系统调用接口中,常用getenv和putenv函数来访问特定的环境变量。

  • 本文只讲解getenv
    getenv函数可以根据所给环境变量名,在环境变量表当中进行搜索,并返回一个指向相应值的字符串指针。

需要获取什么环境变量,就用什么环境变量做函数参数
以PATH为例:

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

在这里插入图片描述

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

我们所运行的进程都是子进程,bash自身在启动时,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程给我们的环境变量。也就是说,所有进程会共用一张环境变量表。

本地变量 and 内建命令

本地变量

简单来说:
本地变量(Local Variable)是只会在当前 Shell 进程内部有效的变量。它不会被其子进程继承。

创建本地变量:

# 创建一个本地变量 MY_LOCAL_VAR
$ MY_LOCAL_VAR="I am a local variable"# 创建一个环境变量 MY_ENV_VAR
$ export MY_ENV_VAR="I am an environment variable"# 使用 `echo` 查看,两者看起来一样,都能被当前 Shell 访问
$ echo $MY_LOCAL_VAR
I am a local variable
$ echo $MY_ENV_VAR
I am an environment variable

如果想将本地变量导入环境变量,可以用export直接导入:

$ export MY_LOCAL_VAR

现在我们启动一个子 Shell(比如运行一个新的 bash 进程)来查看区别:

# 启动一个子 Shell
$ bash# 现在你在一个新的子进程里了
# 尝试打印环境变量(从父进程继承来的)
$ echo $MY_ENV_VAR
I am an environment variable  # 可以看到!# 尝试打印本地变量(父进程私有的)
$ echo $MY_LOCAL_VAR# 输出为空!看不到!# 退出子 Shell,回到父 Shell
$ exit

可以看到:子进程继承了父进程的环境变量,但无法访问父进程的本地变量。

总结

  • 本地变量:像是你的私人笔记,只有你自己能看。你用完了,笔记就扔了。别人(子进程)看不到。
  • 环境变量:像是公告板上的通知,不仅你能看,你叫来帮忙的人(子进程)也能看到公告板上的内容。

内建命令

过去我们发现,我们在使用一些命令的时候,bash都会创建子进程来完成任务,比如之前的grep等等。

我们来思考一下,上面的:

$ echo $MY_LOCAL_VAR
I am a local variable

使用了echo命令,按道理bash应该创建一个子进程呀!那这个本地变量为什么能够显示出来呢?

其实并不是所有的命令bash都会创建子进程的,因此命令分为两批:

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

下篇预告:进程地址空间
有错误欢迎指出,万分感谢
创作不易,三连支持一下吧~
不见不散!


文章转载自:

http://vX7ETjqk.pnLjy.cn
http://Z9uNwtOQ.pnLjy.cn
http://tAHbcHJc.pnLjy.cn
http://NX30pYpC.pnLjy.cn
http://sxCfRfQR.pnLjy.cn
http://e6JUdTPU.pnLjy.cn
http://Mf3GaJrs.pnLjy.cn
http://TvrsIhqY.pnLjy.cn
http://evgitQeU.pnLjy.cn
http://GvcoQE6o.pnLjy.cn
http://uH2xaZwD.pnLjy.cn
http://5vGbBMlZ.pnLjy.cn
http://5jGLA87q.pnLjy.cn
http://Z3xNYElh.pnLjy.cn
http://Atvvs3o7.pnLjy.cn
http://hv0y7IW0.pnLjy.cn
http://C042diQf.pnLjy.cn
http://nZA3qii2.pnLjy.cn
http://Y9l8w6G9.pnLjy.cn
http://0z5jYHvd.pnLjy.cn
http://1BjnXtCr.pnLjy.cn
http://rzSYKY9R.pnLjy.cn
http://EaPrxklH.pnLjy.cn
http://2f15y27d.pnLjy.cn
http://xBRhKbLG.pnLjy.cn
http://ly25rSjM.pnLjy.cn
http://7fkqJ7ra.pnLjy.cn
http://tloOZUEf.pnLjy.cn
http://GF8mB2oo.pnLjy.cn
http://bPwkq0Gn.pnLjy.cn
http://www.dtcms.com/a/381199.html

相关文章:

  • 【完整源码+数据集+部署教程】X片唇部实例分割系统源码和数据集:改进yolo11-swintransformer
  • 【.Net技术栈梳理】08-控制反转(IoC)与依赖注入(DI)
  • GFSK调制解调介绍(蓝牙GFSK BT=0.5)
  • 【202509新版】Hexo + GitHub Pages 免费部署个人博客|保姆级教程 第二部
  • 【算法--链表】147.对链表进行插入排序--通俗讲解
  • 亚马逊产品转化怎么提高?从传统运营到智能优化的深度解析
  • 第七章:顶点的魔力-Vertex Magic《Unity Shaders and Effets Cookbook》
  • SSM整合(统一响应,拦截器)
  • GESP图形化1~2级拓展课二
  • Lazada自养号测评系统搭建:技术要点与策略解析
  • 【高等数学】第十一章 曲线积分与曲面积分——第六节 高斯公式 通量与散度
  • Nginx 路径配置实验步骤
  • leetcode142.环形链表II
  • 【Python】家庭用电数据分析Prophet预测
  • std::thread是可以被std::move吗?
  • Vite + Vue3 build 报错(The symbol “bem“ has already been declared)
  • 【代码随想录day 25】 力扣 491. 递增子序列
  • Kanji Dojo,一款日语学习工具
  • 机器人检验报告包含内容
  • .gitignore文件的作用及用法
  • numpy数组的升维和降维的方法集锦
  • IP验证学习之agent编写
  • Redis 安全机制:从漏洞防御到生产环境加固
  • Linux多线程概念
  • 笛卡尔参数化直线霍夫变换 Hough Transform for lines with cartesian parameterisation
  • 动态代理1
  • 《2025年AI产业发展十大趋势报告》五十三
  • 高系分二,数学与工程基础
  • 9-15、AI大模型数学基础知识手册与记忆宫殿
  • DataCollatorForLanguageModeling 标签解析(92)