【Linux】进程优先级、调度、命令行参数:从理论到实践(二)

🌈 个人主页:Zfox_
🔥 系列专栏:Linux

目录

  • 🚀 前言
  • 一: 🔥 进程优先级
    • 🍵 基本概念
    • 🍵 查看系统进程
    • 🍵 PRI and NI
    • 🍵 PRI vs NI
    • 🍵 用top命令更改已存在进程的nice:
    • 🍵 为什么Linux优先级调整会被限制?
    • 🍵 其他概念
  • 二:🔥 进程调度切换
    • 🍵 进程切换
    • 🍵 进程调度
      • ✈️ 位图判断
      • ✈️ 过期队列
    • 📒✏️总结
  • 三:🔥 命令行参数
  • 四:🔥 共勉

🚀 前言

  • 🐲 接着上一篇博客我们继续往下学习,点击跳转上一篇博客 【Linux】进程管理:从理论到实践(一)

一: 🔥 进程优先级

🍵 基本概念

  • 🍊 cpu资源分配的先后顺序,就是指进程的优先级(priority)。
  • 🍊 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
  • 🍊 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

🍵 查看系统进程

💦 在linux或者unix系统中,用 ps –l 命令则会类似输出以下几个内容:
在这里插入图片描述
我们很容易注意到其中的几个重要信息,有下:

  1. UID : 代表执行者的身份
  2. PID : 代表这个进程的代号
  3. PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  4. PRI代表这个进程可被执行的优先级,其值越小越早被执行
  5. NI代表这个进程的nice值
  6. Linux的默认优先级是80

🍵 PRI and NI

  • PRI 也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高。
  • NI 呢? 就是我们所要说的 nice 值了,其表示进程可被执行的优先级的修正数值。
  • PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:RI(new)=PRI(old)+nice
  • 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行。
  • nice所以,调整进程优先级,在Linux下,就是调整进程nice值。
  • nice其取值范围是-20至19,一共40个级别。

🍵 PRI vs NI

  • 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。
  • 可以理解nice值是进程优先级的修正数据。

🍵 用top命令更改已存在进程的nice:

🎯 查看进程优先级指令:

ps -al / l

🎯 调整进程优先级

第一步:top
第二步:输入r
在这里插入图片描述

第三步:输入需要调整优先级的进程id

在这里插入图片描述

第四步:输入想要增加的优先级值(比如输入10,就是优先级就降低10,输入-10,就是优先级就升高10)

在这里插入图片描述

结果:使用ps -al 查看myexePRI发现更改为 90了 NI 值更改为10。

在这里插入图片描述

🍵 为什么Linux优先级调整会被限制?

  • 如果不受限制,自己可以将自己的进程的优先级设置非常高,而系统的,或者别人的非常低,优先级较高的进程获得资源,后续还有很多今后曾源源不断产生,会导致常规进程享受不到资源。造成进程饥饿问题。

🍵 其他概念

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

二:🔥 进程调度切换

🎯 进程在运行的时候,放在CPU上,并不是需要将该进程的代码全部执行完才会被拿下CPU,现代操作系统,都是基于时间片进行轮转执行,一个进程在CPU上有一个执行最大时间,即时间片,在CPU上执行了该时间,就会被拿下。

🍵 进程切换

🍊 CPU里面有大量的寄存器,比如:eax,ebx,ecx,edc,eds/ecs,eip… 等等,当一个进程在CPU 上被运行的时候,这些寄存器会围绕这个进程进行展开运算,保存相关的在执行该进程代码中的信息,临时数据,比如变量,函数等等。

  • 其中 epi 也就是我们所说的 pc指针,记录进程执行到哪里了(比如PC记录的是一个进程代码的50行,则说明当前执行的是第49行)。这能保证进程在切换回来后还是继续往后执行。

  • 当一个进程在CPU上的时间到了,要被拿下CPU时,需要将CPU上关于该进程的所有数据(大多是寄存器上的数据)(被称为进程的硬件上下文)全部保存带走,这些数据有些保存到进程的PCB中,有些保存在其他地方,较为复杂。这个过程叫 保护上下文

  • 这个进程被拿下后,CPU里面的寄存器的数据还是上一个进程的旧数据,当这些寄存器需要存储新的进程的相关数据时,直接覆盖式的写入即可。

  • 如果是首次调度该进程,就直接从代码开头运行即可,如果不是首次调度,进程被放到CPU上运行时,则需要先把上次的硬件上下文数据进行恢复(恢复上下文),然后根据 eip寄存器 中保存的上次代码执行的位置继续执行。

  • CPU内的寄存器只有一套,虽然寄存器数据放在了共享的CPU是设备里面,但是所有的数据,其实都是被进程私有的。

🍵 进程调度

Linux实现进程调度的算法,考虑优先级,考虑饥饿,考虑效率。

  • 🍊 我们来看看Linux的运行队列,如下图(runqueue):

  • 我们首先看蓝色框内的内容,有一个叫做 queue[140] 的数组,这里的 queue数组表示活动状态进程的进程队列。

  • 其中在queue数组中,索引0~99号下标我们是不用的,这是因为0-99号下标对应的是 实时进程的优先级,实时进程是内核里更加重要的进程,放 在前100位由操作系统控制,避免系统抢占的情况。

  • 所以我们只剩下 100-139 这个范围可操控,其实这也就和我们优先级的可控范围大小相同,正好对应队列的四十个空位,而OS通过某种映射关系,将可控优先级映射到数组 100-139的下标。

✈️ 位图判断

🍊 我们看蓝色框内还有一项 bitmap数组,类型为int,这个数组用来干嘛呢?只能存储5个整形变量。

数组的名字叫做bitmap已经很明显了,就是位图,5个整形元素有 32 * 5 = 160 个比特位,比特位的位置,表示哪一个队列。比特位的内容,表示该队列为不为空。

比如:0000 … 0000 ,如果最左侧0对应queue[100]的位置,那么如果该比特位为0表示在该下标映射的优先级下该队列为空,否则不为空。

有人会问:为什么要用位图?

  • 遍历整个队列的时间开销要远大于查找位图。
  • 所以,bitmap是用来检测队列中是否有进程,检测对应的比特位是否为1!

而蓝色框内还有一个元素:nr_active,在Linux中,nr_active 是运行队列中用于表示活跃进程数量的计数器。nr_active 的值可以告诉内核有多少进程正在等待执行,从而帮助内核进行进程调度和资源分配。

✈️ 过期队列

🍊 在红色框中的三项属性与蓝色框中的三项属性完全相同,也就是另外一个队列,被称为——过期队列。

活跃队列表示当前CPU正在执行的运行队列,而 正在执行的运行队列(也就是活跃队列)是不可以增加新的进程的。

所以操作系统设置了一个 和活跃队列相同属性的过期队列,当活跃队列正在执行时如果有进程需要添加进运行队列,那么就会添加至过期队列当中,也就是说 活跃队列的进程一直在减少,而过期队列中的进程一直在增多!

当活跃队列的进程执行完毕后,就会和过期队列进行交换,它们交换的方式是通过两个结构体指针:

  • 就是 active 和 expired 结构体指针,它们分别指向活跃队列和过期队列,而活跃队列与过期队列由于属性完全相同,于是被放在了一个叫做 prio_arry_t[2] 的数组里,prio_arry_t[0]指向活跃队列,prio_arry_t[1]指向过期队列:

  • 当活跃队列被CPU执行完毕后,我们 只需要交换两个指针的内容即可,这样仅仅是指向的内容变了,活跃队列变为过期队列,过期队列变活跃队列,并且时间复杂度为 O(1):

  • 新增进程在过期队列里插入,此时正在执行的是活跃队列,所以这个时候在过期队列里就有时间处理竞争饥饿的问题了。

这样,我们竞争饥饿,优先级,以及进程效率都解决了。

📒✏️总结

  • 进程切换最重要的部分就是进程上下文的保护和恢复。
  • 进程调度的优先级问题由 活跃进程数组的下标与进程优先级形成一种映射关系 解决。
  • 进程调度的时间复杂度问题由 位图和两个结构体指针 解决,时间复杂度控制在了O(1)。
  • 进程调度的进程饥饿问题由活跃队列和过期队列 解决。

三:🔥 命令行参数

🚀 关于命令行参数,在C/C++中,我们main函数能不能带参数?实际上是可以的:

#include <stdio.h>int main(int argc, char *argv[])   //main函数的形参
{return 0;
}
  • main函数参数其中两个参数为 int argcchar *argv[],其中 argv是指针数组,里面存的全是指针变量,这里我告诉你 argcargv 数组的元素个数,那么 argv 数组究竟存着什么东西?我们不妨做个实验:
[lisi@hcss-ecs-a9ee work]$ cat tmp.cpp#include<stdio.h>
#include<stdlib.h>int main(int argc, char *argv[])
{for(int i = 0 ; i < argc ; ++i){printf("argv[%d]:%s\n",i ,argv[i]);}return 0;
}[lisi@hcss-ecs-a9ee work]$ g++ tmp.cpp -o tmp -std=c++11
[lisi@hcss-ecs-a9ee work]$ ./tmp
argv[0]:./tmp
  • 我们发现,argv保存的内容恰好是我们向命令行解释器输入的内容,我们不妨在命令后多加几个选项:
[lisi@hcss-ecs-a9ee work]$ ./tmp -a -l
argv[0]:./tmp
argv[1]:-a
argv[2]:-l

这里的结果就很明显了,bash 将我们命令行参数以空格为分隔符转化为一个个的子串,并且 argv里的每一个指针按照顺序指向不同的子串。

说到字符串,我们无论实在Linux还是Windows或者其他系统,都有命令行提示符,他们是怎么构成的?我们输入的命令被转化成了一整个字符串,以空格作为分隔符,将整个字符串转化为一个一个的子串。

所以这样也能获取到我们的命令行参数。现在我们知道了C语言 main函数中两个参数是由bash维护并创建和传参的。但是为什么要这么做?

我们以下面一段代码来帮助理解:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>//实现不同的算数功能
int main(int argc, char* argv[])
{if (argc != 4){printf("Usage:\n\t%s -[add|sub|mul|div] x y\n\n", argv[0]);}int x = atoi(argv[2]);int y = atoi(argv[3]);if (strcmp("-add", argv[1]) == 0){printf("%d + %d = %d\n", x, y, x + y);}else if (strcmp("-sub", argv[1]) == 0){printf("%d - %d = %d\n", x, y, x - y);}else if (strcmp("-mul", argv[1]) == 0){printf("%d * %d = %d\n", x, y, x * y);}else if (strcmp("-div", argv[1]) == 0){printf("%d / %d = %d\n", x, y, x / y);}else{printf("unknown!\n");}return 0;
}
  • 上面是我们根据输入的命令行参数的选项来做不同功能的函数:
    在这里插入图片描述

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

这个功能是不是很像我们的指令?(比如:ls 指令)为什么我们指令可以根据不同的选项而做出不同的动作?原因就在于我们的选项传递到main函数中的 argc 和 argv当中,所以能够完成同一个指令根据不同选项做出对应的功能,所以,选项的本质就是命令行参数!

四:🔥 共勉

以上就是我对 【Linux】进程优先级、调度、命令行参数:从理论到实践(二) 的理解,会立刻更新下一篇的,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉
在这里插入图片描述

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

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

相关文章

【数据管理】数据脱敏解决方案(word原件)

1 概述 1.1 数据脱敏定义 1.2 数据脱敏原则 1.2.1基本原则 1.2.2技术原则 1.2.3管理原则 1.3 数据脱敏常用方法 3.1.1泛化技术 3.1.2抑制技术 3.1.3扰乱技术 3.1.4有损技术 1.4 数据脱敏全生命周期 2 制定数据脱敏规程 3 发现敏感数据 4 定义脱敏规则 5 执…

本科生已不够 AI公司雇佣各领域专家训练大模型

9月29日消息&#xff0c;人工智能模型的性能在很大程度上依赖于其训练数据的质量。传统方法通常是雇用大量低成本劳动力对图像、文本等数据进行标注&#xff0c;以满足模型训练的基本需求。然而&#xff0c;这种方式容易导致模型在理解和生成信息时出现“幻觉”现象&#xff0c…

<<迷雾>> 第5章 从逻辑学到逻辑电路(5)--异或门 示例电路

!ABA!B 的逻辑电路组成 info::操作说明 鼠标单击开关切换开合状态 注: 这个实际就是 异或门, 当两个输入相异时输出高电平, 否则输出低电平 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/cyjsjdmw-examples/assets/circuit/cyj…

读数据湖仓04数据架构与数据工程

1. 大容量存储器 1.1. 几乎是到最后时刻&#xff0c;大容量存储器才被引入基础数据的基础设施中 1.1.1. 分析人员通常不会直接在大容量存储器中进行数据分析 1.1.2. 大容量存储器在基础数据中扮演的角色也特别重要&#xff0c;它能够在许多方面支持数据分析人员自由灵活地完成…

从零开始搭建UVM平台(七)-加入monitor

书接上回&#xff1a; 从零开始搭建UVM平台&#xff08;一&#xff09;-只有uvm_driver的验证平台 从零开始搭建UVM平台&#xff08;二&#xff09;-加入factory机制 从零开始搭建UVM平台&#xff08;三&#xff09;-加入objection机制 从零开始搭建UVM平台&#xff08;四&…

Github 2024-10-02C开源项目日报 Top9

根据Github Trendings的统计,今日(2024-10-02统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目9BitBake项目1Netdata: 开源实时监控平台 创建周期:4020 天开发语言:C协议类型:GNU General Public License v3.0Star数量:68982 个For…

JAVA开源项目 周边产品销售网站 计算机毕业设计

本文项目编号 T 061 &#xff0c;文末自助获取源码 \color{red}{T061&#xff0c;文末自助获取源码} T061&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

【算法】0/1背包问题

背包中有一些物品&#xff0c;每件物品有它的价值与重量&#xff0c;给定一个重量&#xff0c;在该重量范围内取物品&#xff08;每件物品不可重复取&#xff09;&#xff0c;求最大价值。 将需求转化为表格&#xff0c;每一行中的每个格子代表可选哪些下标的物品在总重量限额内…

VMware Aria Operations 8.18 发布,新增功能概览

VMware Aria Operations 8.18 - 多云 IT 运维管理 通过统一的高性能平台&#xff0c;实现跨私有云、混合云和多云环境的 IT 运维管理。 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-aria-operations/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出…

营业执照显示经营异常怎么回事

经营异常是怎么回事&#xff1f;是什么意思&#xff1f;首先&#xff0c;我们要明确什么是公司经营异常。简单来说&#xff0c;就是公司在经营过程中出现了一些问题&#xff0c;导致公司无法正常运营。这些问题可能包括未按规定报送年度报告、未按规定公示有关信息等。那么&…

资源《Arduino 扩展板1-LED灯》说明。

资源链接&#xff1a;Arduino 扩展板1-LED灯 1.文件明细&#xff1a; 2.文件内容说明 包含&#xff1a;AD工程、原理图、PCB。 3.内容展示 4.简述 该文件为PCB工程&#xff0c;采用AD做的。 该文件打板后配合Arduino使用&#xff0c;属于Arduino的扩展板。 该文件主要有…

Vue 路由设置

为了防止遗忘&#xff0c;记录一下用Vue写前端配置路由时的过程&#xff0c;方便后续再需要用到时回忆。 一、举个例子 假如需要实现这样的界面逻辑&#xff1a; 在HomePage中有一组选项卡按钮用于导航到子页面&#xff0c;而子页面Page1中有一个按钮&#xff0c;其响应事件是…

C++继承的三种方式[ACCESS]

C继承的定义 两个类的继承关系在派生类中声明&#xff0c;派生类定义使用以下语法&#xff1a; class DerivedClass: [ACCESS] BaseClass{ /…/ }; 冒号&#xff08;:&#xff09;后的[ACCESS]是继承的最高权限级别符&#xff0c;可以是以下三个值&#xff08;存取权限级别&am…

业务封装与映射 -- ODUflex

ODUflex&#xff0c;即灵活速率光数字单元&#xff0c;带宽范围1.25G~100G。目前ITU-T G.709定义了两种形式的ODUflex&#xff0c;基于固定比特速率业务的ODUflex (CBR)和基于包业务的ODUflex (GFP)。 ODUflex特点 高效承载 提供灵活可变的速率适应机制。用户可根据业务大小&…

5. 常用开源数据集快速导入Linux服务器(AutoDL)——深度学习·科研实践·从0到1

目录 1. 查找公开数据 2. 解压到自己的数据盘中 3. 解压常用指令 1. 查找公开数据 参考文档&#xff1a;AutoDL帮助文档-公开数据查找和导入 AutoDL提供了部分常用开源数据&#xff0c;供咱在实例中进行使用&#xff0c;免去下载上传的烦恼&#xff08;直接解压到咱的服务…

OpenAi FunctionCalling 案例详解

源码详细讲解 pdf 及教学视频下载链接&#xff1a;点击这里下载 FunctionCalling的单一函数调用 天气预报查询&#xff08;今天长沙的天气如何&#xff1f;&#xff09; import json import requests from openai import OpenAIclient OpenAI()location "长沙"…

鸿蒙开发知识点速记全解

入门 1、API涵盖应用框架、系统、媒体、图形、应用服务、AI六大领域。 应用框架相关Kit开放能力&#xff1a;Ability Kit&#xff08;程序框架服务&#xff09;、ArkUI&#xff08;方舟UI框架&#xff09;等。系统相关Kit开放能力&#xff1a;Universal Keystore Kit&#xf…

24-10-1-读书笔记(二十一)-《契诃夫文集》(四)下([俄] 契诃夫 [译] 汝龙) 我爱你,娜坚卡。

文章目录 《契诃夫文集》&#xff08;四&#xff09;下&#xff08;[俄] 契诃夫 [译] 汝龙 &#xff09;目录阅读笔记记录总结 《契诃夫文集》&#xff08;四&#xff09;下&#xff08;[俄] 契诃夫 [译] 汝龙 &#xff09; 十月第一篇&#xff0c;放假了&#xff0c;挺高兴的&…

四、I/O控制方式

1.程序直接控制方式 完成一次读/写的过程 CPU千预频率 每次I/O的数据传输单位 数据流向 优缺点 CPU发出I/0命令后需要不断轮询 极高 字 设备→CPU→内存 内存→CPU→设备 优点:实现简单。在读/写指令之后&#xff0c;加上实现循环检查的一系列指令即可(因此才称为“程…

WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!

前言 今天大姚给大家分享一套基于.NET 8.0 LayUI的快速开发框架&#xff0c;项目完全开源、免费&#xff08;MIT License&#xff09;且开箱即用&#xff1a;WaterCloud。 可完全实现二次开发让开发更多关注业务逻辑。既能快速提高开发效率&#xff0c;帮助公司节省人力成本&…