【Linux深入剖析】进程优先级 | 命令行参数 | 环境变量

news2025/2/27 23:07:44

📙 作者简介 :RO-BERRY
📗 学习方向:致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持


在这里插入图片描述


目录

  • 1.进程优先级
  • 2.Linux下的进程优先级
    • 调整优先级
  • 3.进程切换
    • 3.1进程特性
    • 3.2寄存器
    • 3.3 进程切换的过程
  • 4 命令行参数
  • 5.利用main函数参数实现简易计算器
  • 6.环境变量
    • 6.1 基本概念
    • 6.2 环境变量的分类
    • 6.3 查看环境变量


1.进程优先级

进程优先级就是进程要访问某种资源,进程进行通过一定的方式(排队),确认享受资源的先后顺序
CPU资源分配的先后顺序,就是值进程的优先权(priority)
优先权高的进程有优先执行的权力。

配置进程优先权对多任务环境的Linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体的性能。

为什么要有优先级?

因为CPU资源有限,一台普通的电脑上CPU是4~8个,而要执行的进程少说也要20个以上,所以要让重要的进程优先执行,保证利益的最大化。


2.Linux下的进程优先级

在Linux或unix系统中,用ps -al指令则会类似输出以下几个内容:

在这里插入图片描述

  • UID:代表执行者的身份,用户标识符
  • PID:代表这个进程的代号
  • PPID:代表这个进程是由那个进程发展衍生而来的,亦即父进程的代号
  • PRI:代表这个进程可被执行的优先级,其值越小越早被执行
  • NI:代表这个进程的nice值

PRI 和 NI

  • PRI(priority),即进程的优先级,就是程序被CPU执行的先后顺序,此值越小进程的优先级越高
    每个普通进程的PRI默认值为80
  • NI(nice),表示进程可被执行的优先级的修正数值
  • nice值默认基本都是0
  • PRI值越小越快被执行,加入nice值后,将会使得PRI变为:PRI = 80 + nice
  • 当nice为负数时,该进程的优先级将会变小,即期优先级会变高,则其越快被执行
  • 调整优先级,在Linux下,就是调整进程的nice值
  • nice其取值范围是-20~19 ,一共40个级别(一般不会去改nice值,一直使用默认值)

nice值之所以有范围,为了防止优先级被调整过度,时每次先使用CPU都是同一批进程,其它进程没办法更好的调度执行,所以过渡器 不允许过度调整nice值

调度器主要功能:较均衡的让每个进程都可以使用CPU推进代码,而不能使一个或几个进程产生偏差
所以,优先级对于我们来说并不是很重要,我们一般写代码也几乎不回去调整优先级

注意

进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
可将nice理解为是进程优先级的修正数据

关于优先级PRI着重强调

Linux默认优先级是80
Linux的优先级是可以修改的,Linux的优先级的范围(60,99]
Linux优先级本质是数字,数字越小,优先级越高

调整优先级

调整方法非常多,可以使用代码去调整,也可以用指令去调,这里我们讲一下使用top去调整进程的优先级
写一个简单程序
myprocess.c

 1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 int main()
  5 {
  6   while(1)
  7   {
  8       printf("I am process, pid: %d\n",getpid());                                       
  9       sleep(1);
 10   }
 11 }

makefile

myprocess:myprocess.c
		gcc -o $@ $^ #-std=c99
.PHONY:clean
clean:
	rm -f myprocess

使用make指令生成可执行文件myprocess,之后按照下面的步骤做

  1. 执行该文件
  2. 使用ps -la查看对应进程的PID
  3. 使用top指令打开top
  4. 进入top后,按“r”
  5. 输入进程PID,回车
  6. 输入需要调整的nice值,回车
  7. 按q退出top
  • 使用ps -la查看对应进程的PID
    在这里插入图片描述
  • 使用top指令打开top
    在这里插入图片描述
  • 进入top后,按“r”
    在这里插入图片描述
  • 输入进程PID,回车
    在这里插入图片描述
  • 输入需要调整的nice值,输入10回车,然后按q退出top再次使用ps -la查看对应进程的PID
    在这里插入图片描述

PRI变为90,并且NI变为10

注意:
如果调整的nice值过大,那调整的值默认为19
如果调整的nice值过小,那调整值默认为-20
每次修改调整值,最终的PRI都是80加上nice值

Linux为什么调整优先级是有一个范围的?
进程饥饿问题

如果不加限制,那么将自己的进程优先级调整的非常高,别人的优先级调整的非常低,每个人都会想把自己的程序优先级调到最高,优先级较高的进程,会优先得到资源,但是后续还有源源不断的进程产生,常规进程就会很难享受到CPU资源,就会导致进程饥饿问题


3.进程切换

3.1进程特性

  • 竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了搞小完成任务,更合理竞争相关资源,便具有了优先级。
  • 独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰
  • 并行:多个进程在多个CPU下分别、同时进行运行,这称之为并行。
  • 并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

3.2寄存器

一个CPU里面存在很多的寄存器寄存器,寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果以及一些CPU运行需要的信息。
寄存器主要分为:通用寄存器、标志寄存器、指令寄存器、段寄存器、控制寄存器、调试寄存器、描述符寄存器、任务寄存器、MSR寄存器

通用寄存器

eax: 通常用来执行加法,函数调用的返回值一般也放在这里面
ebx: 数据存取
ecx: 通常用来作为计数器,比如for循环
edx: 读写I/O端口时,edx用来存放端口号
esp: 栈顶指针,指向栈的顶部
ebp: 栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量
esi: 字符串操作时,用于存放数据源的地址
edi: 字符串操作时,用于存放目的地址的,和esi两个经常搭配一起使用,执行字符串的复制等操作

标志寄存器

标志寄存器,里面有众多标记位,记录了CPU执行指令过程中的一系列状态,这些标志大都由CPU自动设置和修改:

  • CF 进位标志
  • PF 奇偶标志
  • ZF 零标志
  • SF 符号标志
  • OF 补码溢出标志
  • TF 跟踪标志
  • IF 中断标志

指令寄存器

eip: 指令寄存器可以说是CPU中最最重要的寄存器了,它指向了下一条要执行的指令所存放的地址,CPU的工作其实就是不断取出它指向的指令,然后执行这条指令,同时指令寄存器继续指向下面一条指令,如此不断重复,这就是CPU工作的基本日常。

段寄存器

段寄存器与CPU的内存寻址技术紧密相关。

控制寄存器

控制寄存器是CPU中一组相当重要的寄存器,我们知道eflags寄存器记录了当前运行线程的一系列关键信息。那CPU运行过程中自身的一些关键信息保存在哪里呢?答案是控制寄存器!

调试寄存器

在x86/x64CPU内部,还有一组用于支持软件调试的寄存器。

描述符寄存器

所谓描述符,其实就是一个数据结构,用来记录一些信息,‘描述’一个东西。把很多个描述符排列在一起,组成一个表,就成了描述符表。再使用一个寄存器来指向这个表,这个寄存器就是描述符寄存器。

任务寄存器

CPU内部设置了一个专用的寄存器——任务寄存器TR,它指向当前运行的任务

MSR寄存器

从80486之后的x86架构CPU,内部增加了一组新的寄存器,统称为MSR寄存器,中文直译是模型特定寄存器,意思是这些寄存器不像上面列出的寄存器是固定的,这些寄存器可能随着不同的版本有所变化。这些寄存器主要用来支持一些新的功能。

3.3 进程切换的过程

  1. 计算机调度某个进程时,CPU 会把这个进程的 PCB 地址加载到某个寄存器,也就是说,CPU内有寄存器可以只找到进程的PCB地址。
  2. CPU里有一个 eip 寄存器(PC指针),指向当前执行指令的下一条指令的地址。
  3. 当进程在运行的时候,一定会产生非常多的临时数据,这些临时数据只属于当前进程,这些临时数据会放在CPU的寄存器中。CPU内部的所有的临时数据我们称做为硬件上下文
  4. 进程在调度的时候占有CPU,但是却不是一直占有到进程结束,进程都有自己的时间片,有了时间片就可以实现高效率调度,因为时间片的存在,进程会出现没有被执行完就被拿下去的情况。
  5. 当进程被换下去的时候,进程的运行信息会被存在操作系统里面,以便下次CPU重新调度时进程能够正常运行,这叫做进程的上下文保护。
  6. 在进程第二次被CPU调度的时候,首先要做的第一件事情就是读取操作系统中进程运行的相关数据,这叫做进程的上下文恢复,然后进程就会继续上次没执行完的任务开始运行。

注意:

CPU内的寄存器只有一套,区分寄存器以及寄存器的内容,这两个是不一样的,我们运行进程使用这一套寄存器并且产生临时数据,当进程离开的时候,这些临时数据一并带走存入操作系统,当次进程再次运行的时候,数据重新拿出来。
但是寄存器内部保存的数据可以有多套,虽然寄存器数据放在了一个共享的CPU设备里,但是所有的数据,其实都是被进程私有的!进程和进程之间使用同一个CPU以及寄存器,但是其中的数据不是共享的。


4 命令行参数

请你回想一下写C语言代码的时候,我们的主函数main函数带参数吗?我们一般写main函数里面不带参数也就是void参数对吧?
其实main函数默认是带参数的函数

#include<stdio.h>
int main(int argc,char *argv[])
{
		return 0
}

我们这样直接运行代码是能跑的
这里的char *argv就是一个指针数组,int argc则代表了这个指针数组里有多少个成员
这里面存的是什么呢?
我们来试着打印一下

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

运行结果
在这里插入图片描述
其演变过程如下:
在这里插入图片描述
这就是我们bash维护的命令行参数表


那到底为什么要这样做呢?

请看下面的例子:

#include<stdio.h>
#include<string.h>

//要实现三种不同的功能
// ./myprocess -3
int main(int argc,char *argv[])
{
  if(argc != 2)
  {
    printf("Usage:\n\t%s -number[1-3]\n",argv[0]);
    return 1;
  }
  if(strcmp("-1",argv[1]) == 0)
  {
    printf("function 1\n");
  }
  else if(strcmp("-2",argv[1]) == 0)
  {
    printf("function 2\n");
  }
  else if(strcmp("-3",argv[1]) == 0)
  {
    printf("function 3\n");
  }
  else
  {
    printf("unKnow!\n");
  }
  return 0;
}

运行结果
在这里插入图片描述
通过这个代码片段我们已经实现了简单的功能:

我们可以通过不同的选项,让我们的同一个程序执行它内部不同的功能

我们这样使用程序,有没有觉得眼熟呢?
在这里插入图片描述
我们使用的这些Linux指令不也是这样使用的吗?
我们指令后面的这些选项让我们可以实现指令的不同的功能

所以指令后面的这些选项的本质是我们的命令行参数!!!!

命令行参数是我们Linux选项指令的基础

5.利用main函数参数实现简易计算器

既然main函数参数可以读到命令行
中输入的字符串,所以可以用代码实现
一个简易的计算器,代码如下:

#include<stdio.h>    
#include<string.h>    
#include<stdlib.h>    
int main(int argc,char* argv[])    
{    
    if(argc!=4)    
    {    
        printf("%s OP[add|sub|mul|div] d1 d2\n",argv[0]);    
        return 1;    
    }    
    int x=atoi(argv[2]);    
    int y=atoi(argv[3]);    
    if(strcmp(argv[1],"add")==0)    
        printf("%d + %d = %d\n",x,y,x+y);    
    else if(strcmp(argv[1],"sub")==0)    
        printf("%d - %d = %d\n",x,y,x-y);    
    else if(strcmp(argv[1],"mul")==0)    
        printf("%d * %d = %d\n",x,y,x*y);    
    else if(strcmp(argv[1],"div")==0)                                                                                                                                   
        printf("%d / %d = %d\n",x,y,x/y);    
    else    
        printf("输入操作符错误");    
    return 0;    
}    

使用方法:

  1. 用户必须先输入可执行程序:a.out
  2. 第二个字符串输入加减乘除其中一个
  3. 第三,第四个字符串输入操作数
  4. 若其中有一个环节输入错误会报提醒

在这里插入图片描述

6.环境变量

6.1 基本概念

环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但 是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找;
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
程序(操作系统命令和应用程序)的执行都需要运行环境,这个环境是由多个环境变量组成的。

6.2 环境变量的分类

按生效的范围分类

系统环境变量:公共的,对全部的用户都生效。
用户环境变量:用户私有的、自定义的个性化设置,只对该用户生效。

按生存周期分类

永久环境变量:在环境变量脚本文件中配置,用户每次登录时会自动执行这些脚本,相当于永久生效。
临时环境变量:使用时在Shell中临时定义,退出Shell后失效。

6.3 查看环境变量

我们来先思考一个问题

  • 为什么我们myprocess可执行文件前面需要加上./
  • Linux指令在使用的时候不需要在前面加上./

这是因为我们系统在执行myprocess文件的时候是去查找了,但是没找到,所以我们在前面加上./或者绝对路径就可以运行了,所以我们想执行一个程序系统需要先找到

这不得不引出一个概念: 环境变量
保存程序的默认搜索路径的环境变量
叫做:
PATH

在运行程序时,系统会去PATH中
找当前可执行程序在不在这些路径中
如果在就直接执行程序,不在就报错

使用指令查看PATH

echo $PATH

****加粗样式****
这个路径是以无数个子路径组成,路径之间以冒号进行分隔
系统在这些路径下都找不到你的程序就会报错
所以只能通过./告诉系统我们在这个路径下查找

所以要想我们的指令像系统指令一样运行
我们可以将自己写的程序的路径加入
到环境变量PATH中!
注意:我们进行拷贝需要root的权限,普通用户使用指令需要sudo

使用指令:

sudo cp myprocess /usr/bin/

**加粗样式**

我们刚刚是拷贝数据到默认路径下实现我们的程序可以像系统指令一样运行起来
那我们可不可以把我们的工作目录也加入到默认搜索路径下面呢?那我们就不用每一次都要一个一个程序去加入默认路径了

使用指令: PATH = $PATH:要添加的路径

在这里插入图片描述

请注意,当你将你的路径添加后
下次重启时又会恢复为默认路径
所以想一劳永逸的话可以将你自己
的可执行程序放入默认的路径中!

查看所有环境变量
使用指令

env

**加粗样式**
可以看到这里很多,看的眼花缭乱,我们并不需要每一个都认识,我们简单认识几个:

  • 1.环境变量PWD

为什么我们可以使用pwd查看当前目录呢?
这是因为存在pwd环境变量,当你访问目录这个环境变量会自动更新

  • 2.环境变量USER

为什么我们使用whoami指令就会打出当前用户的用户名呢?
这是因为我们的环境变量USER,它记录了我们登入Linux的用户的用户名信息

  • 3.环境变量HOME

为什么我们使用cd ~就可以访问我们的家目录呢?
这是因为我们有环境变量HOME,他记录着我们当前用户的家目录

学习之路还很漫长,如果我的文章对你有所帮助的话,不妨关注加三连给我一个支持,感谢各位IT大佬

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python Matplotlib Tkinter-->tab切换2

环境 python:python-3.12.0-amd64 包: matplotlib 3.8.2 pillow 10.1.0 import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import tkinter as tk import tkinter.ttk as ttk# 创建自定义工具栏类 c…

护眼台灯如何选择?超全护眼台灯选购攻略分享

近年来护眼台灯的存在感非常强&#xff0c;已然成为家家户户必不可少的一盏灯具&#xff0c;如今市面上的台灯款式多得让人数不清&#xff0c;不过也正是如此&#xff0c;也导致了许多不专业不合格的产品混杂在其中&#xff0c;这类劣质台灯对光源的控制很差&#xff0c;使亮度…

【简写Mybatis】02-注册机的实现以及SqlSession处理

前言 注意&#xff1a; 学习源码一定一定不要太关注代码的编写&#xff0c;而是注意代码实现思想&#xff1a; 通过设问方式来体现代码中的思想&#xff1b;方法&#xff1a;5W1H 源代码&#xff1a;https://gitee.com/xbhog/mybatis-xbhog&#xff1b;https://github.com/xbh…

Qt程序设计-钟表自定义控件实例

本文讲解Qt钟表自定义控件实例。 效果如下: 创建钟表类 #ifndef TIMEPIECE_H #define TIMEPIECE_H#include <QWidget> #include <QPropertyAnimation> #include <QDebug> #include <QPainter> #include <QtMath>#include <QTimer>#incl…

Collectors.toMap的value为空报NullPointerException

1、现象 import lombok.Data; import org.apache.commons.lang3.StringUtils;import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collect…

Ps:索引颜色模式

Ps菜单&#xff1a;图像/模式/索引颜色 Image/Mode/Indexed Color 索引颜色 Indexed Color模式可生成最多 256 种颜色的 8 位图像文件。 这种颜色的限制使得索引颜色模式的图像文件相比于全彩图像&#xff08;如 RGB 颜色模式下的图像&#xff09;具有更小的文件大小&#xff0…

学习磁盘管理

文章目录 一、磁盘接口类型二、磁盘设备的命名三、fdisk分区四、自动挂载五、扩容swap六、GPT分区七、逻辑卷管理八、磁盘配额九、RAID十、软硬链接 一、磁盘接口类型 IDE、SATA、SCSI、SAS、FC&#xff08;光纤通道&#xff09; IDE, 该接口是并口。SATA, 该接口是串口。SCS…

Neoverse S3 系统 IP:机密计算和多芯片基础设施 SoC 的基础

第三代Neoverse系统IP Neoverse S3 产品推出了我们的第三代基础设施特定系统 IP&#xff0c;这是下一代基础设施 SOC 的理想基础&#xff0c;适用于从 HPC 和机器学习到 Edge 和 DPU 的各种应用。S3 机箱专注于为我们的合作伙伴提供 Chiplet、机密计算等关键创新以及 UCIe、DD…

使用R语言进行多元线性回归分析-多重共线的诊断

一、数据集 序号X1x2x3x4Y序号X1x2x3X4Y12666078.57831224472.51229155274.31954182293.12356850104.3111047426115.92143184787.6111140233483.8155263395.971266912113.311655922109.2111368812109.410771176102.73       1、从中选取主要变量&#xff0c;建立与因变…

NVM存储设备MTBF介绍

1. 概念 1.1. MTBF MTBF(Mean Time Between Failure)&#xff0c;平均故障间隔时间&#xff0c;也被称为平均无故障时间&#xff0c;是衡量一个产品的可靠性指标&#xff0c;其单位为小时。其定义为&#xff1a;产品在总的使用阶段累计工作时间与故障次数的比值&#xff1a; …

【软件测试】--功能测试2--常用设计测试用例方法

一、解决穷举场景 重点&#xff1a;使用等价类划分法 1.1 等价类划分法 重点&#xff1a;有效等价和单个无效等价各取1个即可。 步骤&#xff1a;1、明确需求2、确定有效和无效等价3、根据有效和无效造数据编写用例 1.2 案例&#xff08;qq合法验证&#xff09; 需求&#xff…

展厅设计在零售领域发挥哪些关键作用

1、 陈列和布局 零售展示设计的成功始于合适的陈列和布局。展厅设计公司考虑产品的类型、大小和特点&#xff0c;以创建有吸引力的展示。产品陈列应使顾客能够轻松浏览和访问。 2、色彩和照明 色彩和照明是零售展示设计的关键元素。展示区域的色彩和照明方案应与品牌形象一致&a…

GEE入门篇|遥感专业术语(实践操作4):光谱分辨率(Spectral Resolution)

目录 光谱分辨率&#xff08;Spectral Resolution&#xff09; 1.MODIS 2.EO-1 光谱分辨率&#xff08;Spectral Resolution&#xff09; 光谱分辨率是指传感器进行测量的光谱带的数量和宽度。 您可以将光谱带的宽度视为每个波段的波长间隔&#xff0c;在多个波段测量辐射亮…

雾锁王国Enshrouded多人联机专用服务器配置要求

雾锁王国/Enshrouded服务器CPU内存配置如何选择&#xff1f;阿里云服务器网aliyunfuwuqi.com建议选择8核32G配置&#xff0c;支持4人玩家畅玩&#xff0c;自带10M公网带宽&#xff0c;1个月90元&#xff0c;3个月271元&#xff0c;幻兽帕鲁服务器申请页面 https://t.aliyun.com…

GCC如何产生core dump

先决条件 1.安装apport&#xff08;automatically generate crash reports for debugging&#xff09; 2.修改/etc/security/limits.conf文件&#xff0c;使允许core dump&#xff0c;或者用ulimit -c unlimited设置core dump文件的大小为unlimited&#xff08;临时方案&#x…

【分享】WinRAR解压缩软件的3个密码功能

WinRAR是一款功能强大的解压缩软件&#xff0c;除了用来解压缩文件&#xff0c;还可以作为加密软件&#xff0c;给压缩包设置密码&#xff0c;达到保护文件的目的。今天来分享一下WinRAR的3个密码功能&#xff0c;一起来看看吧&#xff01; 功能一&#xff1a;设置“打开密码”…

TP6书写+uni前端,最新版本圈子系统,搭载各种插件,APP小程序H5公众都可以打包拥有,源码交付,支持二开!

部分插件展示 群聊插件 单独频道功能说明&#xff1a; 1、可申请建群。后台审核&#xff0c; 2、群分为自由加入和审核加入&#xff0c;由群主审核。 3、群聊天内容保存到数据库。 4、可查看附近的群&#xff0c;需要用户开启定位。 5、群主可踢人和禁言。 6、支持每个人提示音…

使用Scrapy将数据提取到数据库中,进行处理

我们将数据处理的方式&#xff0c;最开始csv文件 再到与数据库建立联系 代码&#xff1a; Spider: import scrapyclass ShuangseqiuSpider(scrapy.Spider):name "shuangseqiu"allowed_domains ["sina.com.cn"]start_urls ["https://view.lottery…

17.材质和外观

1.图形学中的材质 在图形学中&#xff0c;材质&#xff08;Material&#xff09;是用来描述物体外观和表面特性的属性集合。它包含了控制光的反射、折射、吸收以及其他光学效果的信息&#xff0c;从而决定了物体在渲染过程中的外观。 渲染方程中那一项和材质有关&#xff1f; …

【白话前端】数字孪生(web端)常用技术栈和软件列举

通常友友们看到我发的好看的可是化图片&#xff0c;经常问我是怎么实现的&#xff0c;用的什么软件&#xff0c;其实还真不是一项技术和一个软件就能达成的&#xff0c;这次我分享下web端的技术栈和软件&#xff0c;下次分享桌面端的。 3D建模软件&#xff1a; 数字孪生需要建…