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


📙 作者简介 :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.cgcc -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://xiahunao.cn/news/2812541.html

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

相关文章

[C++]使用C++实现监控文件是否被修改

软件开发过程中经常会用到配置文件,某些应用场景要求在软件运行时动态修改配置文件,此时就需要监控配置文件是否被修改,下面我们就来看看如何使用C实现这一功能吧 软件开发过程中经常会用到配置文件&#xff0c;某些应用场景要求在软件运行时动态修改配置文件&#xff0c;此时…

国产服务器操作系统

为何记录 最近的开发工作经常接触到国产服务器操作系统的业务&#xff0c;经常被x86、arm、龙芯、鲲鹏、欧拉...搞得一脸懵逼&#xff0c;遂记之&#xff01; 操作系统 这里按照应用场景分&#xff1a; 桌面操作系统&#xff1a;主要用于pc&#xff0c;如Windows、macOS、Li…

MES系统生产订单管理:多角度全面解析

一、MES系统生产订单管理概述 MES中的生产订单管理涉及到订单的接收、处理、执行和跟踪等多个方面。MES系统生产订单管理旨在确保生产过程中的订单信息准确无误、生产进度可控&#xff0c;从而实现高效、有序的生产。 二、生产订单管理的核心功能 订单接收与处理&#xff1a;…

30-k8s集群的七层代理-ingress资源(进阶知识)

一、ingress概述 1&#xff0c;引发问题 目前使用svc资源做网络暴露&#xff0c;使用nodeport类型&#xff0c;一个业务对应一个宿主机端口&#xff0c;那么如果业务多了&#xff0c;所占用的宿主机端口也就多了&#xff0c;虽然说宿主机端口一般情况下都是够用的&#xff0c;…

Android Jni的介绍和简单Demo实现

Android Jni的介绍和简单Demo实现 文章目录 Android Jni的介绍和简单Demo实现一、JNI的简单介绍JNINDKJni的开发背景&#xff1a;**JNI在 Android 开发里的主要应用场景&#xff1a;** 二、JNI的简单Demo1、Demo主要界面和效果展示2、CMake编译加载文件add_library 指令的加载库…

主从复制实现Redis集群

主从复制实现Redis集群实验 (一主二从): 实验环境: 使用Docker 搭建 Redis 版本 5.0.5 打开一个终端窗口&#xff0c;在其中运行如下命令创建一个名为redis-master的Redis容器。注意&#xff0c;它的端口是6379 (本地的端口:映射到容器的端口) docker run -itd--name redis-m…

深入理解 JavaScript 对象原型,解密原型链之谜(下)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

VScode连接远端服务器一直输入密码解决方法

文章目录 1 关闭远程连接2打开命令面板3 输入remote-ssh: kill vs code server on host… 1 关闭远程连接 2打开命令面板 3 输入remote-ssh: kill vs code server on host… remote-ssh: kill vs code server on host… 然后一路回车(选中出问题的主机)&#xff0c;输一遍密码…

缓存一致性问题的解决策略

缓存一致性问题的背景和概念介绍 在一个系统中&#xff0c;我们通常使用数据库来存储数据&#xff0c;以保证数据的持久性。但是&#xff0c;由于数据库的读写速度相对较慢&#xff0c;如果每次请求都直接访问数据库&#xff0c;会降低系统的响应速度。为了提高系统的性能&…

《TCP/IP详解 卷一》第7章 防火墙和NAT

7.1 引言 NAT通常改变源IP和源端口&#xff0c;不改变目的IP和目的端口。 7.2 防火墙 常用防火墙&#xff1a; 包过滤防火墙&#xff08;packet-filter firewall&#xff09; 代理防火墙&#xff08;proxy firewall&#xff09; 代理防火墙作用&#xff1a; 1. 通过代理服务…

Spring全面精简总结

Spring两大核心功能&#xff1a;IOC控制反转、AOP面向切面的编程 控制反转(loC&#xff0c;Inversion of Control)&#xff0c;是一个概念&#xff0c;是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器&#xff0c;通过容器来实现对象的装配和管理。控制反转就是…

雾锁王国Enshrouded服务器几核几G够用?

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

three中界面交互gui.js库的使用

gui.js库(可视化改变三维场景) dat.gui.js说白了就是一个前端js库&#xff0c;对HTML、CSS和JavaScript进行了封装&#xff0c;学习开发的时候&#xff0c;借助dat.gui.js可以快速创建控制三维场景的UI交互界面&#xff0c;你打开课件中案例源码体验一下就能感受到。 学习dat…

C++笔记(二)--- 继承和组合

目录 C三种继承方式 构造函数 析构 继承 public继承 protected继承 private继承 组合 访问权限 构造/析构函数调用顺序 初始化 总结 C三种继承方式 C有三种继承方式&#xff1a;public protected private 属性方式为 class [派生类名称] : [继承方式] [继…

嵌入式驱动学习第一周——git的使用

前言 本文主要介绍git的使用&#xff0c;包括介绍git&#xff0c;gitee&#xff0c;以及使用gitee创建仓库并托管代码 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&#xf…

StarRocks实战——多维分析场景与落地实践

目录 一、OLAP 系统历史背景 1.1 历史背景与痛点 1.2 组件诉求 二、StarRocks 的特点和优势 2.1 极致的查询性能 2.2 丰富的导入方式 2.3 StarRocks 的优势特点 三、多维分析的运用场景 3.1 实时计算场景 / 家长监控中心 3.2 实时更新模型选择 3.2.1 更新模型UNIQU…

一般情况下,硬件中使用Repeating Sequence出现波形很奇怪就是数据的周期频率和mcu运行的频率不一致导致的

一般情况下&#xff0c;出现波形很奇怪就是数据的周期频率和mcu运行的频率不一致导致的 把timer values 修改为0 1就好了&#xff0c;如果是0&#xff0c;0.1就不行&#xff0c;不会有下面的波形

15:00面试,15:06就出来了,问的问题过于变态了。。。

我从一家小公司转投到另一家公司&#xff0c;期待着新的工作环境和机会。然而&#xff0c;新公司的加班文化让我有些始料未及。虽然薪资相对较高&#xff0c;但长时间的工作和缺乏休息使我身心俱疲。 就在我逐渐适应这种高强度的工作节奏时&#xff0c;公司突然宣布了一则令人…

新加坡大带宽服务器概览

随着全球互联网的迅猛发展&#xff0c;服务器作为支撑网络应用的重要基础设施&#xff0c;扮演着越来越重要的角色。新加坡&#xff0c;作为亚洲四小龙之一&#xff0c;其服务器市场也备受关注。特别是新加坡的大带宽服务器&#xff0c;更是受到了众多企业和个人的青睐。那么&a…

Python 实现Excel自动化办公(上)

在Python 中你要针对某个对象进行操作&#xff0c;是需要安装与其对应的第三方库的&#xff0c;这里对于Excel 也不例外&#xff0c;它也有对应的第三方库&#xff0c;即xlrd 库。 什么是xlrd库 Python 操作Excel 主要用到xlrd和xlwt这两个库&#xff0c;即xlrd是读Excel &am…