(13)Linux 进程的优先级、进程的切换以及环境变量等

前言:我们先讲解进程的优先级。然后讲解进程的切换,最后我们讲解环境变量,并且做一个 "让自己的可执行程序不带路径也能执行"的实践,讲解环境变量的到如何删除,最后再讲几个常见的环境变量。

一、进程优先级(Process Priority)

1、什么是优先级?

cpu资源分配的先后顺序就是指进程的优先级(priority)

先区分优先级和权限的区别:

  • 优先级代表一定能得到申请的资源
    只是现在要考虑得到资源的时间问题

  • 权限代表有没有资格得到申请的资源
    是要考虑能否的问题

2、为什么会存在优先级?

我们不妨先思考下我们日常生活中排队的本质,排队的本质可以说是 "确定优先级" ,

而插队行为就是更改优先级。因为排队造就了优先级,那我们为什么要排队?

现实生活中一旦出现了抢,就难免会引发争执。

所以,排队主要是换了一种竞争方式,不以那么残酷的方式竞争,让进程都能井然有序

因为 系统里面永远都是进程占大多数,资源是少数。 这就导致了进程竞争资源是常态!

排队和进程资源竞争都是一定要确认先后的,它们的本质都是 确认优先级

本章我们要讲的是 Linux 的进程优先级,Linux 下的优先级有很多方式,包括设置和修改。

我们不建议修改优先级,如果你不懂调度器的调度算法,你随便修改优先级其实就是变相地 "插队" 了。你可以让你的进程尽快地得到了某种 CPU 资源或其它资源,凡是可能会打破调度器的平衡。其实你在用户层再怎么设置,也不会对调度器的调度策略产生什么影响。

3、查看系统进程:ps -l

**查看系统进程:**在 Linux 或者 Unix 系统中,输入 ps -l 命令则会输出内容:

cpp 复制代码
$ ps -l    # 查看进程的优先级

我们写一个简单的 Hello 程序,令其每隔一秒发送一次 Hello:

cpp 复制代码
#include <stdio.h>
#include <unistd.h>
 
int main(void) {
    while (1) {
        sleep(1);
        printf("Hello world! pid: %d\n" ,getpid());
    }
}

我们把它运行起来,此时我们使用 ps -l 查看:

然而,并没有我们的的进程

因为 ps -l 只能显示当前终端下进程的相关信息,我们可以使用给它加上 ​ 选项:

cpp 复制代码
$ ps -la   

此时我们的进程 process 就显示出来了,我们重点关注 ​ 和 ​ 列。

Linux 中的进程优先级由两部分组成:

  • :优先级 (priority),默认进程优先级为
  • :nice 值 (nice value) ,进程优先级的修正属性,取值区间为 ,默认值为

**注意:**数字越小,表示优先级越高;数字越大,优先级越低。(Linux 下)

优先级的部分我们在 task_struct 中也是可以找到的。

它的优先级和我们上一章讲的进程状态一样,也是个整数,在 task_struct 中表示:

4、进程优先级的修改

要更该进程的优先级,需要更改的是 ​,而非 ​ 。

因为 nice 值是进程优先级的修正数据,所以一个进程不管是在启动前还是在运行中,想要修改优先级,都是通过修改它的 nice 值来达到目的。

使用一连串指令修改指定进程的优先级:

  1. 输入top启动任务管理器
  2. 输入r(renice)来修改NI的值
  3. 再输入目标进程的pid来定位
  4. 输入想要修改的NI值(注意不是输入PRI值)

其实,我们系统中是存在 nice 命令的,对应的还有 renice 。

cpp 复制代码
$ nice  
$ renice

它们可以让我们在启动一个进程时直接指定优先级,或者启动中或启动前设置优先级。

感兴趣可以自行查阅,我们还是主要学习如何使用 top 命令去修改:

cpp 复制代码
$ top

注:系统允许优先级的值被改高
如果想要将值改低要用sudo或root账号

进入 top 后我们键入 ​ ,此时会发出询问:PID to renice [default pid=]

在后面输入我们要修改的进程的 ​ 即可,我们刚才进程的 ​ 是 ​:27428.

然后会询问:PID to renice [default pid=1] 问你要设置哪个进程的 ​:

如果你没有提供权限,会

如果你执意修改,你须具备 超级用户 的权限 ------ ​ !这里我们 sudo top 就行:

cpp 复制代码
$ sudo top 

我们来演示一下,给他增加10。

值得强调的是,Linux 不允许用户无节制地设置优先级,设置的优先级范围不能逾过下列区间:

二、进程的切换(Process Switch)

CPU 资源只有少量,甚至一个,所以进程之间是具有竞争属性的。为了高效的完成任务、更合理竞争相关资源,便具有了优先级。进程运行具有独立性,不会因为一个进程挂掉或者异常而导致其它进程出现问题!

**思考:**那么操作系统是如何做到进程具有独立性的呢?

1、并行和并发

并发:

当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。

特点:对单处理器而言--多个程序在同一时间段发生

并行:

当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

特点:对多处理器而言--多个程序在同一时刻发生

2、进程抢占

**思考:**OS 就是简单的根据队列来进行前后调度的吗?有没有可能突然来了一个优先级更高的进程?

正在运行的低优先级进程,可能正在享受着它的时间片、推进着代码,但是如果来了优先级更高的进程,我们的调度器会直接把对应的进程从 CPU 上剥离,放上优先级更高的进程,这个操作就叫做 进程抢占

a. 不允许不同优先级的进程存在的

b. 相同优先级的进程,是可能存在多个的

现在我们思考两个问题:

  1. 没运行完的进程数据后来去哪儿了?
  2. 当一个进程被取下时``它在CPU的数据是否会被删除?

举个例子:

cpp 复制代码
int func() {
    int a = 10 + 20;
    return a;
}
 
int z = func();

z 是如何得到已经释放的临时变量 a 的数据的?

寄存器功不可没,拷贝一份到寄存器里去,然后再 mov 给 z 变量。

CPU 内的寄存器是:可以临时地存储数据

寄存器分为 可见寄存器不可见寄存器

当进程在被执行的过程中,一定会存在大量的临时数据,会暂存在 CPU 内的寄存器中。

寄存器上数据的重要性:

我们把进程在运行中产生的各种寄存器数据,我们叫进程的硬件上下文数据。

  • 当进程被剥离:需要保存上下文数据
  • 当进程恢复时:需要将曾经保存的上下文数据恢复到寄存器中。

一个进程被取下来时CPU并不会删除它的临时数据而是当下一个进程被放入时,用
下一个进程的数据将上一个进程的数据覆盖了!

三、环境变量(Environment Var)

**思考:**为什么我们的代码运行要带路径,而系统的指令不用带路径?

如果我们直接输入我们的可执行程序,会显示 :

我们说过,执行系统的指令实际上也是程序,系统的指令你也是可以带上路径的:

其实,我们可以通过它的报错 "command not found" 发现些什么!

要执行一个可执行程序,前提是要先找到它。

现在我们的问题就可以转化成:为什么系统的命令能找到,而我们自己的程序找不到?

系统中是存在相关的 环境变量,保存了程序的搜索路径的!

为什么我们的代码运行要带路径,而系统的指令不用带?其本质是由环境变量 PATH

引起的!

1、环境变量 PATH

我们可以通过 env 指令查看环境变量:

cpp 复制代码
$ env

(一大堆数据)

这些变量每一个都有它特殊的用途,系统中搜索可执行程序的环境变量叫做 PATH。

我们可以通过 grep 去抓一下:

cpp 复制代码
$ echo $PATH

如何查看环境变量的内容?我们可以使用 echo 去显示:

cpp 复制代码
$ echo $PATH

环境变量 PATH中会承载多种路径,中间用冒号 ( : ) 作为分隔符。

我们再执行某一个程序时,比如执行 ls 时,我们的系统识别到 ls 的输入时,会在上面路径中逐个搜索,只要在特定的路径下找到了 ls,就会执行特定路径下的 ls 并停止搜索。

换言之,PATH 就提供了环境变量,可执行程序搜索的路径。

我们的 lsusr/bin 路径下,这说明当前的 ls 在 PATH

中是可以被找到的,

所以执行 ls 的时侯自然可以不带路径,所以我们自己的 process 不带路径自然就不能执行。

因为当前的 process 所在的路径并没有这里的环境变量,程序在搜索的时侯找了路径也没有找到你这个可执行程序,搜索完找不到,自然就报 "command not found" 了。

现在就想让我的可执行程序 process 不带路径直接执行起来

我们先讲述一种简单粗暴的方式,直接把我们的可执行程序 cp 拷贝到系统的路径中:

cpp 复制代码
$ sudo cp process /usr/bin/

既然系统的所有命令都在 usr/bin 路径下,那我们把我们的 process 拷进去就行了。

不建议你将你的指令拷贝到 Linux 系统路径下,因为这会污染 Linux 下的命令池。

更好的方式是将 process 所处的路径也添加到环境变量中。

在 Linux 命令行中,我们也是可以定义变量的,命令行变量分为两种:

  • 普通变量
  • 环境变量(具备全局属性)

Linux命令行也是可以定义变量的

用系统查看环境变量的命令 env 去查看一下这个本地变量,会发现根本找不到,

因为它不以环境变量的形式存在,但是它是存在的!

如果你想让一个变量变成环境变量,你可以通过 export 导出一个在系统中可以查看的环境变量:

cpp 复制代码
$ export []=[]

通过 env 并 grep 一下这个变量,我们就能找到我们导出的环境变量了:

把我们的环境变量,当前路径导入到 PATH 路径中看看会发生什么:

cpp 复制代码
$ export PATH=[路径]

我们发现我们的 process 可以跟系统指令一样不带路径直接执行了,但是但是但是

你会发现你的命令全都不能用了。(ls,touch,mkdir,,,,,)

因为你把 PATH 里的环境变量都搞没了,只剩你自己的路径了,所以这些指令自然都找不到了。

出现了你刚才自己可执行程序不带路径后 Enter 的报错 "command not found" 。

在命令行上设置的环境变量是具有临时性的,只在你登陆期间有效。

关掉重启!!!就能解决

如果你想让你的环境变量设置永久有效的话,是需要更改配置文件的,该配置文件在系统当中,跟云服务器没有关系。

cpp 复制代码
$ export PATH=$PATH:[路径]

2、环境变量的导入和解除

刚才我们通过 export 去导入变量,如果想取消一个变量,就可以使用 unset 来取消变量设置:

此时我们使用 unset 环境变量,就可以解除 foo:

" 这些东西实际上都是 shell 命令,export 是导出,unset 是取消 "

3、介绍几个常见的环境变量

下面我们来详细介绍一下常见的环境变量,刚才我们就是用 env 指令去查看环境变量的:

这个 HOSTNAME 就是表示 "对应这台主机的主机名" 。

我们同样也是可以通过 echo 指令带上 $ 去查看环境变量:

cpp 复制代码
echo $HOSTNAME

再比如 SHELL,它可以告诉你你的 shell 在哪里,通常是 /bin/bash

cpp 复制代码
echo $SHELL

得益于 Linux 存在历史命令的记录功能,我们可以在 Xshell 里 ↑ ↓ 显出历史命令,就像这样:

Linux 最多允许你记录的历史命令条数是 10000。(有的就不一样唉)

而我们接下来要介绍的 HISTSIZE (History Size),就是定义一共记录多少历史指令的环境变量:

cpp 复制代码
$ echo $HISTSIZE

当然还有很多,比如 SSH-CLIENT 记录了谁登的服务器、地址、端口号等。

尾记

命令行中启动的进程,父进程全部都是 bash 。

环境变量具有全局属性,环境变量是会被子进程继承下去的。

所谓的本地变量,本质就是在 bash 内部定义的变量,不会被子进程继承下去。

Linux 下大部分命令都是通过子进程的方式执行的,但是还有一部分命令不通过子进程的方式执行,而是由 bash 自己执行(调用自己的对应的函数来完成特定的功能,比如 cd 命令),我们把这种命令叫做 内建命令。

相关推荐
存储服务专家StorageExpert3 分钟前
DELL SC compellent存储的四种访问方式
运维·服务器·存储维护·emc存储
hakesashou39 分钟前
python如何比较字符串
linux·开发语言·python
Ljubim.te1 小时前
Linux基于CentOS学习【进程状态】【进程优先级】【调度与切换】【进程挂起】【进程饥饿】
linux·学习·centos
cooldream20091 小时前
Linux性能调优技巧
linux
大G哥1 小时前
记一次K8S 环境应用nginx stable-alpine 解析内部域名失败排查思路
运维·nginx·云原生·容器·kubernetes
长天一色1 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
醉颜凉1 小时前
银河麒麟桌面操作系统修改默认Shell为Bash
运维·服务器·开发语言·bash·kylin·国产化·银河麒麟操作系统
QMCY_jason2 小时前
Ubuntu 安装RUST
linux·ubuntu·rust
慕雪华年2 小时前
【WSL】wsl中ubuntu无法通过useradd添加用户
linux·ubuntu·elasticsearch
苦逼IT运维2 小时前
YUM 源与 APT 源的详解及使用指南
linux·运维·ubuntu·centos·devops