Linux 进程优先级
- 为什么要有优先级的划分?
- Linux 环境设置优先级的具体做法
- 并发运行
- 环境变量
- 如何通过代码获取环境变量
- 环境变量的来源
为什么要有优先级的划分?
优先级的规定就是为了确定某种资源获取的先后顺序。
本质原因是因为CPU资源是有限的。进程数量太多时,就会对资源形成竞争,就需要有优先级的划分来分配资源。
优先级反映到程序中也只是 PCB 结构体(LInux环境下是 task_struct)中定义的一些数据。
Linux 环境设置优先级的具体做法
以下面代码为例查看优先级。
#include <stdio.h>
#include <unistd.h> int main()
{ while(1) { printf("hello world: %d\n", getpid()); sleep(1); } return 0;
}
一个进程的优先级有 PRI 和 NI 共同决定。
PRI 越小,优先级越高,也越先被执行。
NI 是对 PRI 做调整的,也就是说 Linux 下的优先级是可变的。
NI 的取值范围为 -20~19。
修改 NI 的方法有很多,这里使用top
命令来修改。
下面是对 NI 值进行修改后查看到的进程的 PRI。从这里可以体现出 NI 对于进程优先级的调整方式。
并发运行
并行是指多个进程在多个CPU下分别同时运行。
并发是指多个进程在一个CPU下采用进程切换的方式,在一段时间内,多个进程都得以推进。
这里要谈的一点是,进程被切换之后,进程如果还没有被执行结束,那这个进程之后在CPU上恢复执行的时候,它是从头开始执行,还是从之前未执行完的地方开始执行?如果是从未执行完的地方恢复执行,又是如何做到这种恢复的呢?
首先回答第一个问题,肯定不能是从头开始执行了。
要知道用户所使用的计算机通常都只有一个CPU。
假如进程A正在被执行,CPU内的寄存器一定保存的是进程A的执行的各种临时数据。(寄存器中的临时数据,叫做进程的上下文数据)
当进程A被切换下来的时候,进程A需要同时带走自己的上下文数据暂时保存。
这是为了等下次回来继续被运行的时候,能根据这些保存的上下文数据,继续按照之前执行的逻辑向后执行,就好像没有被中断过一样。
所以CPU只有一个,寄存器中的数据也只能存储一份,但是上下文数据可以有多份,这些数据对应不同的进程,从而能够实现并发的运行。
环境变量
先以一个问题作为切入。
我们所写的可执行程序,和系统的可执行程序其实都是一样的存在。
这些可执行程序在执行的时候,都可以带全路径。
但是系统的可执行程序还可以直接执行,不用指定具体路径。而我们所写的可执行程序就必须指明路径(./
路径)。
这是为什么呢?我们所写的可执行程序能不能不指定具体路径就执行呢?
首先要明确的是,系统要执行一条命令,必须要先找到它。
我们所写的可执行程序如果不带路径,就无法被找到。而系统的命令是默认可以被找到的。
因为这些系统命令已经是在环境变量PATH
中存放的路径下的。
像ls
命令就存放在/usr/bin
路径下。
所以要想让我们所写的可执行程序不带路径,有两种做法。
第一种是将我们所写的可执行程序配置进PATH
环境变量的路径下(不推荐,可能会污染命令池)。
第二种是将我们所写的可执行程序的路径放进PATH
环境变量中。
这里要说明一下命令行中改环境变量只在本次登录期间有效。当退出重新登陆后又会恢复修改前的样子。
PATH
只是环境变量的一种。
要查看Linux下所有的环境变量,可以使用env
命令。
这些环境变量在系统当中都是以键值对的形式存在着。
set
命令也可以查看环境变量。同时还可以显示本地定义的shell变量。
如何通过代码获取环境变量
#include <stdio.h>
#include <unistd.h>int main(int argc, char* argv[], char* env[])
{/** 方法一* argc argv 命令行参数* env 环境变量参数*/for (int i = 0; env[i]; ++i){printf("env[%d]: %s\n", i, env[i]);}/** 方法二* environ 全局的第三方变量*/extern char** environ;for (int i = 0; environ[i]; ++i){printf("env[%d]: %s\n", i, env[i]);}return 0;
}
上面的代码获取的是所有的环境变量。
还可以使用getenv
指定要获取的环境变量。
#include <stdio.h>
#include <stdlib.h>int main()
{// 获取 PATH 环境变量printf("%s\n", getenv("PATH"));return 0;
}
这里再介绍一下 main 函数的argc
和argv
参数。
#include <stdio.h>int main(int argc, char* argv[], char* env[])
{for (int i = 0; i < argc; ++i) {printf("argv[%d]: %s\n", i, argv[i]);}return 0;
}
这里可以看到,argc
表示在命令行中传入的参数个数,而argv
内则会保存这些传入的参数。
这里就可以理解,指令对应不同的参数选项,所具有的不同的功能是如何做到的了。
环境变量的来源
环境变量具有全局属性。
任何在命令行上启动的进程,他的环境变量都来自父进程。
默认,所有的环境变量都会被子进程继承。
下面的执行结果给出了一定的证明。
#include <stdio.h>int main()
{printf("%s\n", getenv("helloworld"));return 0;
}
而追溯到源头,命令行shell外壳的环境变量来自操作系统,操作系统会将配置文件中的环境变量进行装载。