文章目录
-
- 一、进程优先级
-
- 优先级是什么?
- 为什么需要优先级?
- 怎么控制进程优先级?
-
- 查看进程优先级
- [PRI and NI](#PRI and NI)
- [PRI vs NI](#PRI vs NI)
- 用top命令修改进程的nice
- 用renice命令修改进程的nice值
- 二、环境变量
-
- 基本概念
- 常见环境变量
- 查看环境变量方法
- 测试PATH
- 测试HOME
- 测试SHELL
- 和环境变量相关的一些命令
- 环境变量的组织方式
- 通过代码获取环境变量
- 通过系统调用获取特定环境变量
- 环境变量通常是具有全局属性的
- [本地变量 and 内建命令](#本地变量 and 内建命令)
一、进程优先级
优先级是什么?
优先级就是获取某种资源的先后顺序。
进程优先级就是进程获取CPU资源分配的先后顺序,进程获取CPU资源分配的先后顺序,就是指进程的优先权(priority),优先权高的进程有优先执行的权力。
为什么需要优先级?
主要原因是因为资源是有限的。
即需要进程优先级的主要原因就是CPU资源是有限的。
竞争性:因为CPU资源是有限的,而进程是多个的,所以进程之间是具有竞争属性的
操作系统为了高效完成任务,让进程良性竞争相关资源,,于是便有了优先级。
如果一个进程长时间得不到CPU资源,该进程的代码会长时间得不到推进,造成该进程的饥饿问题。存在该问题的操作系统是低效的。
怎么控制进程优先级?
查看进程优先级
在Linux或者Unix操作系统中,用ps -l
命令会类似输出以下几个内容:
bash
ps -l

我们很容易注意到其中的几个重要信息,如下:
- UID:代表执行者的身份
- PID:代表这个进程的id
- PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
- PRI:代表这个进程可被执行的优先级,其值越小越早被执行
- NI:代表这个进程的nice值
PRI and NI
- PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
- 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
- PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:
P R I ( n e w ) = P R I ( o l d ) + n i c e PRI(new)=PRI(old)+nice PRI(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中的任务管理器,它能够动态实时的显示系统当中进程的资源占用情况。
修改步骤:
- 进入top后按'r'
- 输入需要修改进程的PID
- 输入nice值
用renice命令修改进程的nice值
使用renice命令,后面跟上更改后的nice值和进程的PID即可
注意: 若是想使用renice命令将NI值调为负值,也需要使用sudo命令提升权限。
二、环境变量
基本概念
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
例如,我们在编写C/C++代码的时候,在链接时,从来不知道我们所链接的动静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,并且在系统当中通常具有全局特性。
常见环境变量
- PATH:指定命令的搜索路径
- HOME:指定用户的主工作目录(即用户登录到Linux系统中时默认的目录
~
) - SHELL:当前shell,它的值通常是
/bin/bash
查看环境变量方法
可以通过echo命令来查看环境变量,如下:
bash
echo $NAME //NAME为需要查看的环境变量名称

测试PATH
我们知道,我们平时使用的命令本质也就是一个一个的可执行程序,然而我们使用命令却不带./
就可以执行,而我们自己生成的可执行程序必须要在前面加上./
才能执行。
./的作用是什么?没错,就是告诉系统可执行程序的位置。
因为 Linux 默认不会在当前目录下寻找可执行程序,而 ./ 明确地告诉系统:"我要运行的程序就在当前目录下"
而命令无需./,系统是如何知道它的位置呢?
就是通过环境变量PATH来找到命令的,查看环境变量PATH我们可以看到如下内容:
可以看到环境变量PATH当中有多条路径,这些路径由冒号隔开,当你使用ls命令时,系统就会查看环境变量PATH,然后默认从左到右依次在各个路径当中进行查找。
那可不可以让我们自己的可执行程序也不用带路径就可以执行呢?
当然是可以滴!
方式一:将可执行程序拷贝到环境变量PATH的某一路径下。
bash
sudo cp proc /usr/bin

方式二:将可执行程序所在的目录导入环境变量PATH中
用export命令,可以将某个目录导入到环境变量PATH中:
bash
export PATH=$PATH:/home/zhh/process_code

这样,我们无需./就可以执行程序了:
测试HOME
任何一个用户在运行系统登录时都有自己的主工作目录(家目录),环境变量HOME当中即保存的该用户的主工作目录。
普通用户:
超级用户root:
测试SHELL
我们在Linux操作系统当中所敲的各种命令,实际上需要由命令行解释器进行解释,而在Linux当中有许多种命令行解释器(例如bash、sh),我们可以通过查看环境变量SHELL来知道自己当前所用的命令行解释器的种类。
而该命令行解释器实际上也是系统当中的一条命令,当这个命令运行起来变成进程后就可以为我们进行命令行解释。
和环境变量相关的一些命令
- echo:显示某个环境变量值
- export:设置一个新的环境变量
- env:显示所有环境变量
- unset:清除环境变量
- set:显示本地定义的shell变量和环境变量
环境变量的组织方式

每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以'\0'结尾的环境字符串
通过代码获取环境变量
方式一:命令行第三个参数
命令行参数
你可能不知道,main函数其实是有参数的:
因为我们平时几乎用不上它们,所以一般情况下都没有写出来。
其实,这三个参数称为命令行参数
既然argv是一个字符数组指针,我们不妨打印看看内容:
c
#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结合使用就可以根据你所给选项给出不同的提示语:
c
#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函数的第三个参数来获取系统的环境变量。
c
#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声明。
c
#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为例:
c
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%s\n", getenv("PATH"));
return 0;
}

环境变量通常是具有全局属性的
我们所运行的进程都是子进程,bash自身在启动时,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程给我们的环境变量。也就是说,所有进程会共用一张环境变量表。
本地变量 and 内建命令
本地变量
简单来说:
本地变量(Local Variable)是只会在当前 Shell 进程内部有效的变量。它不会被其子进程继承。
创建本地变量:
bash
# 创建一个本地变量 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直接导入:
bash
$ export MY_LOCAL_VAR
现在我们启动一个子 Shell(比如运行一个新的 bash 进程)来查看区别:
bash
# 启动一个子 Shell
$ bash
# 现在你在一个新的子进程里了
# 尝试打印环境变量(从父进程继承来的)
$ echo $MY_ENV_VAR
I am an environment variable # 可以看到!
# 尝试打印本地变量(父进程私有的)
$ echo $MY_LOCAL_VAR
# 输出为空!看不到!
# 退出子 Shell,回到父 Shell
$ exit
可以看到:子进程继承了父进程的环境变量,但无法访问父进程的本地变量。
总结
- 本地变量 :像是你的私人笔记,只有你自己能看。你用完了,笔记就扔了。别人(子进程)看不到。
- 环境变量:像是公告板上的通知,不仅你能看,你叫来帮忙的人(子进程)也能看到公告板上的内容。
内建命令
过去我们发现,我们在使用一些命令的时候,bash都会创建子进程来完成任务,比如之前的grep等等。
我们来思考一下,上面的:
bash
$ echo $MY_LOCAL_VAR
I am a local variable
使用了echo命令,按道理bash应该创建一个子进程呀!那这个本地变量为什么能够显示出来呢?
其实并不是所有的命令bash都会创建子进程的,因此命令分为两批:
- 常规命令:通过创建子进程完成任务
- 内建命令:不创建子进程,而是由bash亲自执行,类似于bash调用了自己写的或者系统提供的函数
下篇预告:进程地址空间
有错误欢迎指出,万分感谢
创作不易,三连支持一下吧~
不见不散!