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

news2024/10/2 10:37:48

🌈 个人主页: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.coloradmin.cn/o/2184229.html

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

相关文章

【Java SE 题库】移除元素(暴力解法)--力扣

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. 题目 2. 解法(快慢“指针”) 3. 源码 4. 小结 1. 题目 给你一个数组 nums 和一个值 val&#xff0c;你需要原地移除所有数值等于 val 的元素。元素的顺…

Pre-trained Models for Natural Language Processing: A Survey

前言 预训练模型给下游任务带来的效果不言而喻&#xff0c;有了预训练模型&#xff0c;我们可以使用它来加速解决问题的过程。正如论文中所说的那样&#xff0c;预训练模型&#xff08;PTMs&#xff09;的出现将自然语言处理&#xff08;NLP&#xff09;带入了一个新时代。本篇…

各种饺子的做法

【羊肉馅水饺】 材料:羊肉1000克、洋葱2个、香油3汤匙、盐适量、姜2片、料酒1汤匙、白胡椒粉、十三香1茶匙、 做法&#xff1a; 1.把羊肉剁成肉馅&#xff0c;羊肉选用带一些肥肉的&#xff0c;味道比较香&#xff0c;如果羊肉比较瘦&#xff0c;可以放一些猪的肥肉一起剁成馅…

【Python】探索自然语言处理的利器:THULAC 中文词法分析库详解

THULAC&#xff08;THU Lexical Analyzer for Chinese&#xff09;是清华大学开发的一款中文词法分析工具&#xff0c;集成了分词和词性标注两大功能。THULAC 拥有强大的分词能力和高效的词性标注&#xff0c;适用于多种中文文本处理场景。该工具能够在保证高准确率的同时保持较…

修复OpenSSH远程代码执行漏洞:版本升级到9.9p1

目录 前言1. 备份配置文件2. 下载 OpenSSH 最新版本3. 编译安装 OpenSSH4. 替换旧版 OpenSSH 并创建符号链接5. 重启 SSH 服务6. 验证安装结果结语参考文章 前言 OpenSSH 是一种广泛使用的远程登录协议&#xff0c;它确保了服务器和客户端之间的安全通信。然而&#xff0c;随着…

Linux驱动开发(速记版)--设备树

第五十二章 初识设备树 52.1 设备树介绍 设备树&#xff08;Device Tree&#xff09;是嵌入式系统和Linux内核中用于描述硬件的一种机制。 设备树概述 目的&#xff1a;描述硬件设备的特性、连接关系和配置信息。 优势&#xff1a;与平台无关&#xff0c;提高系统可移植性和可…

【linux进程】进程优先级命令行参数环境变量

目录 一&#xff0c;进程切换二&#xff0c;进程优先级1. 什么是优先级2. 权限 vs 优先级3. 为什么要有优先级4. 优先级的查看方式 三&#xff0c;命令行参数1. 什么是命令行参数2. 为什么要有命令行参数3. 是谁做的 四&#xff0c;环境变量1. 基本概念2. 常见环境变量3. 查看环…

电商店铺多开自动回复软件

在电商平台上开设多个店铺&#xff0c;即店铺多开&#xff0c;是一种扩展业务和增加销售额的策略。然而&#xff0c;店铺多开需要谨慎规划和执行&#xff0c;以避免违反平台规定和管理上的混乱。以下是如何实现店铺多开的详细步骤和注意事项。 1. 确定多开目标 在决定多开店铺…

[云] Getting Started with Kubernetes - Environment setup 环境配置

启动一个 EC2 实例&#xff0c; 请按照以下步骤操作&#xff1a; 登录 AWS 控制台&#xff1a; 打开浏览器&#xff0c;访问 AWS Management Console 并登录到您的账户。 选择 EC2 服务&#xff1a; 在 AWS 控制台的“服务”菜单中找到并点击“EC2”进入 EC2 Dashboard。 启…

Spark SQL分析层优化

导读&#xff1a;本期是《深入浅出Apache Spark》系列分享的第四期分享&#xff0c;第一期分享了Spark core的概念、原理和架构&#xff0c;第二期分享了Spark SQL的概念和原理&#xff0c;第三期则为Spark SQL解析层的原理和优化案例。本次分享内容主要是Spark SQL分析层的原理…

国内车牌号检测数据集 7800张 车牌识别 带标注 voc yolo

车牌号检测数据集 7800张 车牌识别 带标注 voc yolo 车牌号码检测数据集 名称 车牌号码检测数据集 (License Plate Detection Dataset) 规模 图像数量&#xff1a;7800张图像。类别&#xff1a;无分类&#xff0c;主要针对车牌区域的定位。标注个数&#xff1a;10,000多个标…

Windows 11 的 24H2 更新將帶來全新 Copilot+ AI PC 功能

10 月起率先向 Insider 推出。 微軟今日宣布 Windows 11 的 24H2 更新將從 10 月起陸續開放給不同用戶&#xff0c;其中將包括多項全新 Copilot AI PC 功能。首先是回爐重造的 Recall 回顧&#xff0c;官方在聽取社群意見後對安全性做了進一步加強。現在用戶可以自己選擇是否保…

从小IPD到大IPD

IPD体系实施或变革是一个长期的系统工程&#xff0c;需要坚持“总体规划、分步实施”的原则&#xff0c;业界经常有从“小IPD”到“大IPD”的说法。 像华为当年就是从“产品开发流程”开始推行&#xff0c;就是小范围的“小IPD”&#xff0c;后面逐步扩大为“大IPD”&#xff0…

Ubuntu22.04之mpv播放器高频快捷键(二百七十)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

两个向量所在平面的法线,外积,叉积,行列式

偶尔在一个数学题里面看到求两向量所在平面的法线&#xff0c;常规方法可以通过法线与两向量垂直这一特点&#xff0c;列两个方程求解&#xff1b;另外一种方法可以通过求解两个向量的叉积&#xff0c;用矩阵行列式 (determinant) 的方式&#xff0c;之前还没见过&#xff0c;在…

正则表达式调试工具实战

正则表达式调试工具实战 1、新建工程QWidget工程工程名RegexTool 如果QT不会配置,请参考我的博客,QT配置 Widget.cpp 默认内容如下 2、主界面设计 三行两列,每行采用HBoxLayout作为行布局控件,内部一个Lable控件和一个TextEdit控件,采用VBoxLayout 控件包裹三个HBoxLa…

JWT | JWT 漏洞介绍

关注这个漏洞的其他相关笔记&#xff1a;JWT 漏洞 - 学习手册-CSDN博客 0x01&#xff1a;JWT 漏洞介绍 JWT&#xff08;Json Web Token&#xff09;是用于在网络应用环境间传递声明的一种基于 JSON 的开放标准。它通过使用 JSON 对象进行安全的信息传输&#xff0c;可以用于身…

ChatGPT实时语音将于本周向免费用户推出:OpenAI DevDay 2024详细解读

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

激活函数ReLU,Sigmoid,tanh,softmax性质讲解及使用matplotlib绘制

Sigmoid及tanh sigmoid及tanh的函数图像较为相似,它们的公式如下 Sigmoid公式 tanh公式 Sigmoid及tanh性质解析 Sigmoid和tanh作为激活函数都可以有效完成非线性映射的功效,其中Sigmoid经常作为2分类的神经网络的输出层的激活函数,由于其非线性映射会将输出值转换到0-1的区间…

心觉:潜意识开发为何失败?99%的人卡在理性与感性学习的误区

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作187/1000天 小时候看武侠剧的时候&#xff0c;经常看到剧中有武林高手把绝世武功传给某个涉世未深的铁憨憨主角&#xff0c;比如《天…