【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://www.rhkb.cn/news/264638.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL面试复习】详细说下事务的特性

系列文章目录 在MySQL中&#xff0c;如何定位慢查询&#xff1f; 发现了某个SQL语句执行很慢&#xff0c;如何进行分析&#xff1f; 了解过索引吗&#xff1f;(索引的底层原理)/B 树和B树的区别是什么&#xff1f; 什么是聚簇索引&#xff08;聚集索引&#xff09;和非聚簇索引…

Unity(第六部)向量的理解和算法

标量:只有大小的量。185 888 999 &#xff08;类似坐标&#xff09; 向量:既有大小&#xff0c;也有方向。&#xff08;类似以个体为主体的方向&#xff0c;前方一百米&#xff09; 向量的模:向量的大小。&#xff08;类似以个体为主体的方向&#xff0c;前方一百米、只取一百米…

Leetcoder Day23| 回溯part03:组合+分割

语言&#xff1a;Java/Go 39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的所有不同组合 &#xff0c;并以列表形式返回。你可以按任意顺序返回这些组合。 candidates 中的同一个…

状态机-----

1.原理 同步的意思就是状态的跳转都是在时钟的作用下跳转的&#xff0c;有限是指状态机中状态的个数是有限的。两种状态机的共同点都是状态的跳转只和输入有关&#xff0c;区别就是如果最后的输出只和当前状态有关而与输入无关&#xff0c;则是moore型状态机。如果最后的输出不…

Go 如何按行读取(大)文件?尝试 bufio 包提供的几种方式

嗨&#xff0c;大家好&#xff01;我是波罗学。本文是系列文章 Go 技巧第十七篇&#xff0c;系列文章查看&#xff1a;Go 语言技巧。 本文将介绍 Go 如何按行读取文件&#xff0c;基于此会逐步延伸到如何按块读取文件。 引言 我们将要介绍的按行读取文件的方式其实是非常适合…

Laravel04 eloquent

eloquent 1. eloquent2. 创建eloquent model 以及 取数据 1. eloquent 文档地址&#xff1a; https://learnku.com/docs/laravel/8.x/eloquent/9406 下面是我们&#xff0c;通过laravel的DB类从数据库中获取了post记录&#xff0c;那么有没有可能我们直接获取一个post对象&am…

pycharm控制STM32F103ZET6拍照并上位机接收显示(OV7670、照相机、STM32、TFTLCD)

基于STM32的照相机 准备工作最终效果一、下位机1、主函数2、OV7670初始化 二、上位机1、控制拍照2、接收图片数据 三、资源获取 准备工作 一、硬件及片上资源: 1,串口1(波特率:921600,PA9/PA10通过usb转ttl连接电脑&#xff0c;或者其他方法)上传图片数据至上位机 2,串口2(波特…

一文读懂:AWS 网络对等互连(VPC peering)实用操作指南

VPC peering connection-网络对等互连在您的 Atlas VPC 和云提供商的 VPC 之间建立私有连接。该连接将流量与公共网络隔离以提高安全性。本篇文章有VPC peering的操作指南以及价格等信息。如还有疑问请联系我们MongoDB的销售&#xff0c;客户成功经理或解决方案架构师。 1 使用…

【C之·预处理器】

系列文章目录 文章目录 前言一、预处理指令1. #line的用法1.1 概述 2. #error2.1 概述 二、预定义宏三、示例1. #line2. #error3. 预定义宏 总结 前言 C 预处理器不是编译器的组成部分&#xff0c;但是它是编译过程中一个单独的步骤。简言之&#xff0c;C 预处理器只不过是一个…

C++面试宝典第32题:零钱兑换

题目 给定不同面额的硬币coins和一个总金额amount,编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,则返回-1。说明:你可以认为每种硬币的数量是无限的。 示例1: 输入:coins = [1, 2, 5], amount = 11 输出:3 解释:11 = …

如何使用Douglas-042为威胁搜索和事件应急响应提速

关于Douglas-042 Douglas-042是一款功能强大的PowerShell脚本&#xff0c;该脚本可以提升数据分类的速度&#xff0c;并辅助广大研究人员迅速从取证数据中筛选和提取出关键数据。 该工具能够搜索和识别Windows生态系统中潜在的安全漏洞&#xff0c;Douglas-042会将注意力放在…

Mistral发布语言大模型Mistral Large;法国新星Mistral挑战 OpenAI 霸主地位

&#x1f989; AI新闻 &#x1f680; Mistral发布语言大模型Mistral Large 摘要&#xff1a;Mistral Large 是 Mistral AI 公司最新发布的旗舰语言模型&#xff0c;具备顶尖水平的推理能力。它主要被设计用于处理复杂的多语言推理任务&#xff0c;比如文本理解、转换和代码生…

HTTP---------状态码

当服务端返回 HTTP 响应时&#xff0c;会带有一个状态码&#xff0c;用于表示特定的请求结果。比如 HTTP/1.1 200 OK&#xff0c;里面的 HTTP/1.1 表示协议版本&#xff0c;200 则是状态码&#xff0c;OK 则是对状态码的描述。 由协议版本、状态码、描述信息组成的行被称为起始…

【算法与数据结构】684、685、LeetCode冗余连接I II

文章目录 一、684、冗余连接 I二、685、冗余连接 II三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、684、冗余连接 I 思路分析&#xff1a;题目给出一个无向有环图&#xff0c;要求去掉一个边以后构成一个树&#xf…

【iOS ARKit】ARWorldMap

ARWorldMap 用于存储 ARSession 检测扫描到的空间信息数据&#xff0c;包括地标&#xff08;Landmark&#xff09;、特征点&#xff08;Feature Point&#xff09;、平面&#xff08;Plane&#xff09;等&#xff0c;以及使用者的操作信息&#xff0c;如使用者添加的 ARAnchor …

【非比较排序】计算排序算法

目录 CountSort计数排序 整体思想 图解分析 代码实现 时间复杂度&优缺分析 CountSort计数排序 计数排序是一种非比较排序&#xff0c;不需要像前面的排序一样去比较。 计数排序的特性总结&#xff1a; 1. 计数排序在数据范围集中时&#xff0c;效率很高&#xff0c;但…

golang gin单独部署vue3.0前后端分离应用

概述 因为公司最近的项目前端使用vue 3.0&#xff0c;后端api使用golang gin框架。测试通过后&#xff0c;博文记录&#xff0c;用于备忘。 步骤 npm run build&#xff0c;构建出前端项目的dist目录&#xff0c;dist目录的结构具体如下图 将dist目录复制到后端程序同级目录…

Unity中URP下实现水体(水面高光)

文章目录 前言一、实现高光反射原理1、原理&#xff1a;2、公式&#xff1a; 二、实现1、定义 _SpecularColor 作为高光反射的颜色2、定义 _SpecularIntensity 作为反射系数&#xff0c;控制高光反射的强度3、定义 _Smoothness 作为高光指数&#xff0c;用于模型高光范围4、模拟…

紫外-可见吸收光谱法(UV-Vis)是最常用吸收光谱技术 市场持续扩大

紫外-可见吸收光谱法&#xff08;UV-Vis&#xff09;是最常用吸收光谱技术 市场持续扩大 紫外-可见吸收光谱法&#xff0c;也称为紫外-可见分光光度法&#xff0c;简称UV-Vis&#xff0c;利用样品分子在紫外和可见光激发下产生电子能级跃迁形成的吸收光谱&#xff0c;对元素进行…

Day 2.exec函数族和线程的基本概念、相关函数接口

exec函数族 extern char **environ; int execl(const char *path, const char *arg, ... /* (char *) NULL */); int execlp(const char *file, const char *arg, ... /* (char *) NULL */); int execle(const…