Linux操作系统——进程(四)进程切换与命令行参数

进程切换

概念引入

下面我们先了解几个概念:

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

每一个进程不是占有CPU就一直运行,每隔一段时间自动从CPU上被剥离下来,这里所说的每隔一段时间我们称之为时间片。

Linux内核是支持进程之间进行CPU资源抢占的!

如果CPU正在运行一个优先级为80的进程,然后呢,系统启动了一个优先级更高的进程,优先级为60的一个进程,此时CPU会强制性的将优先级为80的这个进程不管时间片到没到都会把该进程换下去,换成调度那个优先级为60的那个进程进行运行。所以我们的Linux内核的调度的原则呢是基于时间片的轮转式的抢占式内核。

进程这样来回的切换不停的来回切换我们用户是感知不到的看似是同时在运行,其实是因为他们的切换速度非常的快,我们就把这种进程的不断地来回切换不断地运行这种概念呢就叫做 并发。

并发是必定要考虑进程间的切换的!!!

CPU当中呢会存在很多很多的寄存器,比如说,eax,ebx,ecx,edx,ss,ds,cs,gs,fs,ebp,esp,eip,status_reg,cr0~cr4,......等等

假如有如下代码:

#include<stdio.h>int func()
{int a = 10;return a;
}int main()
{int c = func();return 0;
}

为什么我们所写的c语言的函数内定义在栈上的临时变量可以返回给外部?我们都知道栈上的临时变量出了作用域就会被销毁。

原因就在于我们的这个临时变量a的内容再return 的时候是把内容放到了一般是放在eax寄存器上,用来充当代码的临时空间。

那么我们的程序/进程,它怎么知道我们当前运行到了哪里呢?如何做到函数间的跳转的呢?

主要原因是因为呢,我们正常的代码是从上到下运行的,可是我们有循环啊,有判断啊,有函数要进行跳转啊,其实呢,在我们的CPU内有一个寄存器是eip叫做程序计数器,用来保存程序下一条要执行指令的地址。所以说,我们的进程在运行的时候是会使用我们的这些寄存器的,简而言之就是我们的进程会产生各种数据在寄存器内临时保存!

如果我们有多个进程呢?

各个进程在CPU寄存器中形成的临时数据都是不一样的。我们把这些在CPU寄存器中形成的临时数据叫做进程的硬件上下文。

那么CPU的寄存器有几套呢?答案是只有1套。

各个进程的上下文数据有几套呢?答案是多套。

所以你肯定会觉得寄存器只有一套,而进程需要临时保存的数据有多套该如何报错呢?

其实你应该要记住一个重点那就是寄存器!=寄存器的内容。寄存器只有一套但是寄存器保存的数据是可以有多份的。

那么我们下面通过一个故事来进行理解:

故事时刻:

大家呢在上大学的时候呢,我们读大一大二的时候呢,我们国家呢经常有碰到很多部队在学校里面来征兵,然后你可以去当一梁年兵,当了一年兵之后你还可以继续回来上学。到时候毕业的时候呢还可以有当兵经历和自己的学位证,也挺好啊,你和你舍友呢就高兴的去了。你自己可能小时候有一个当兵的梦想,你就去了,你去了之后呢,很不幸,就是比如身体不好,或者近视,或者小时候打架不小心留下了伤疤,总之呢,你没选上,把你刷下来了。你舍友呢选上了,很高兴。那么你舍友会不会在你们打游戏的时候跟你们道个别说:"我要撤了啊,你们玩的开心啊!"你的舍友转身直接第二天就去部队报道了,当他去报道的时候,完蛋了,当了两年兵回来发现他被学校给退学了。

难受的说:"你们怎么回事?我去当兵也不跟学校说一声"。看了下自己的学科学习情况,完蛋了,挂了二十多科,学校的老师每次上课的时候点你舍友名字的时候一直都不在,考试的时候分配座位发现人也不来。为什么舍友去当兵会出现这样的情况?很简单,你去当兵,最起码要跟学校说一声嘛,说一下比如说你的学习情况,当前大一,过了哪几门,有哪些科目正在学要学校给你保留一下学籍状态,比如说学校一共要求学50门课,你已经学了15门了,挂了一门。你像学校申请一下保留学籍,学校呢就说:行吧,你把这个学籍记录保留一下,自己带上吧。你跟舍友好好的吃了顿夜宵,第二天收拾好行李啥的,该带的带走。跟学校把招呼打好,这样去的才算顺利。然后呢,你室友当了一年兵回来了,回来之后直接去上课表里安排的课跟着班上的人上了一学期,到最后发现你室友的考试座位都没有安排,那不完蛋了,白学一学期。原因还是因为回学校了没有跟学校打招呼,回来应该把自己的档案袋上交给学校申请恢复自己的学习情况,这个时候学校会说:"那行吧,给你恢复一下,你的新宿舍给你安排一下,你的新室友给你安排一下" 至此,你室友的学籍状态就被恢复了。那么在这个过程当中,为什么当兵的时候要去保留学籍呢?保留的最终目的都是为了恢复。为什么要恢复呢?因为我们都不想从头再来。那么我们把去当兵之前保留我们的学籍这个过程呢就叫做保留我们进程的上下文,把当兵回来的时候恢复学籍就叫做恢复我们的进程上下文。

把保留学籍去当兵这个过程呢我们就可以理解为进程的切出,把当兵回来恢复学籍这个过程就叫做进程的切入。

不断地进行上述过程就叫做我们进程的上下文切换的过程。

接下来基于这个故事我们就要来谈一谈:

首先我们进程在运行的时候没有运行完的情况下为什么要被切下去?本质是因为调度器要比较均衡的调度运行一些长时间要运行的进程。

当我们进程运行要被切换的时候形成的进程上下文会被保存到寄存器上,那么保存的是寄存器还是寄存器中的内容呢?

答案肯定是寄存器的内容 

将CPU的寄存器数据保存到进程PCB当中(简单理解),本质就是CPU中寄存器的内容保存到了内存当中,因为PCB是在内存当中的。

Linux2.6内核进程调度队列

上图是Linux2.6内核中进程队列的数据结构,之间关系也已经给大家画出来,方便大家理解

一个CPU拥有一个runqueue

如果有多个CPU就要考虑进程个数的负载均衡问题

优先级

普通优先级:100~139(我们都是普通的优先级,想想nice值的取值范围,可与之对应!)
实时优先级:0~99(不关心)

活动队列

时间片还没有结束的所有进程都按照优先级放在该队列nr_active: 总共有多少个运行状态的进程
queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级!
从该结构中,选择一个最合适的进程,过程是怎么的呢?
1. 从0下表开始遍历queue[140]
2. 找到第一个非空队列,该队列必定为优先级最高的队列
3. 拿到选中队列的第一个进程,开始运行,调度完成!
4. 遍历queue[140]时间复杂度是常数!但还是太低效了!
bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个比特位表示队列是否为空,这样,便可以大大提高查找效率!

过期队列

过期队列和活动队列结构一模一样
过期队列上放置的进程,都是时间片耗尽的进程
当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算。

active指针和expired指针

active指针永远指向活动队列
expired指针永远指向过期队列
可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的。
没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程!

在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法!

命令行参数

命令行参数是什么?

下面我们从main函数的传参问题开始说起,那么我们平常c语言写的main函数都是这样的:

int main()
{return 0;
}

那么main函数可以传参吗?

main函数的传参是怎么样的?

下面我们对一段代码来进行解释:

由于main函数它也是一个函数,是函数就可以被调用的,那么同时很正常main函数也可以有自己的形参,其实呢,main函数中的参数可以写成如下形式:

其实这个参数就叫命令行参数,单纯看类型的话,第一个参数是一个int类型的形参变量,而第二个参数是一个字符指针数组。

下面我们对上述两个参数进行使用:

看看它运行结果:

那么这些把我们输入的命令通过计算字符串的个数有几个,那么argv就是多少,把字符串存到一个字符指针数组的形式传到main函数的操作你可以认为是shell 或者操作系统为我们做的。

为什么命令行参数是这样使用的?

下面我们利用main函数中传的命令行参数实现一个加减乘除的小程序,如下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main(int argc, char *argv[])
{if(argc != 4){printf("Use error\nUsage: %s op[-add|sub|mul|div] d1 d2\n", argv[0]); //argv[0], 会不会不存在呢??return 1;}int x = atoi(argv[2]);int y = atoi(argv[3]);int result = 0;// 你的程序一定有4个命令行参数,第一个是程序名if(strcmp(argv[1], "-add") == 0){result = x + y;printf("%d+%d=%d\n", x, y, result);}else if(strcmp(argv[1], "-sub") == 0){result = x - y;printf("%d-%d=%d\n", x, y, result);}else if(strcmp(argv[1], "-mul") == 0){result = x * y;printf("%d*%d=%d\n", x, y, result);}else if(strcmp(argv[1], "-div") == 0){if( 0 == y ) printf("%d/%d=error! div zero\n", x, y);else printf("%d/%d=%d\n", x, y, x/y);}else{printf("Use error, you should use right command line\nUsage: %s op[-add|sub|mul|div] d1 d2\n", argv[0]); //argv[0], 会不会不存在呢??}return 0;
}

然后运行起来:

这个小程序就实现了。

所以呢,相应的我们通过输入以下命令以及所带的选项:

他会以不同的方式进行打印。

所以我们所理解的命令+选项是指的什么呢?

其实就是第一个参数是我们的命令,后面所跟的是这个命令所带的选项,最后都会被传递到main函数的那两个参数,进行判断我们输入的命令然后执行相应的操作。

同时windows中的cmd命令也是通过输入的命令+选项也是命令行参数的使用。

如果我们想要实现一个自己的touch命令,你也可以的。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>int main(int argv,char* argc[]) 
{  if(argc != 2) {printf("touch: missing file operand\n");return 1;}FILE *fp = fopen(argv[1], "w");if(fp != NULL) fclose(fp);return 0;
}

运行起来的效果:

这样我们的touch命令简单的实现了。

总结:命令行参数,可以支持各种指令级别 的命令行选项的设置!

所以呢我们终于理解了历史学的指令,选项是什么关系了。

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

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

相关文章

阶段七-GitEE

Git&#xff1a;版本控制软件 Git的优点 1.1 协同修改 多人并行不悖的修改服务器端的同一个文件。 1.2 数据备份 不仅保存目录和文件的当前状态&#xff0c;还能够保存每一个提交过的历史状态。 1.3 版本管理 在保存每一个版本的文件信息的时候要做到不保存重复数据&…

【开源】基于JAVA的学校热点新闻推送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 新闻类型模块2.2 新闻档案模块2.3 新闻留言模块2.4 新闻评论模块2.5 新闻收藏模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 新闻类型表3.2.2 新闻表3.2.3 新闻留言表3.2.4 新闻评论表3.2.5 新闻收藏表 四、系统展…

W5500-EVB-Pico评估版介绍

文章目录 1 概述2 板载资源2.1 硬件规格2.2 硬件规格2.3 工作条件 3 参考资料3.2 原理图3.3 尺寸图 (单位 : mm)3.4 参考例程 4 硬件协议栈优势 1 概述 W5500-EVB-Pico是基于树莓派RP2040和完全硬连线TCP/IP控制器W5500的微控制器开发板-基本上与树莓派Pico板相同&#xff0c;但…

深度学习(七):bert理解之输入形式

传统的预训练方法存在一些问题&#xff0c;如单向语言模型的局限性和无法处理双向上下文的限制。为了解决这些问题&#xff0c;一种新的预训练方法随即被提出&#xff0c;即BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;。通过在大规模…

Qt Creator可视化交互界面exe快速入门2

上一期介绍的通过代码的方式实现一个简单界面&#xff0c;需要敲小几十行代码&#xff0c;显然是效率低的&#xff0c;这期就介绍下Qt Creator的作用。 Qt Creator的使用&#xff1a; 首先打开我们的Qt Creator 然后点击创建项目&#xff0c;在项目Application里面选择Qt Wid…

嵌入式奇妙之旅:Python与树莓派编程深度探索

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在这个数字化的时代&#xff0c;嵌入式系统的应…

Lua的垃圾回收机制详解

Lua 是一种轻量级的编程语言&#xff0c;广泛用于嵌入到其他应用程序中&#xff0c;尤其是在游戏开发领域。Lua 的内存管理机制采用了自动垃圾收集&#xff08;Garbage Collection&#xff09;的方法。以下是Lua内存管理的一些关键方面&#xff1a; 垃圾收集原理概述 Lua 使用…

matlab设置colorbar标题的两种方式

%% 第一种 figure; A rand(3,4,3); A1 A(:,:,1); A2 A(:,:,2); A3 A(:,:,3); contourf(A1,A2,A3,30); colormap(jet);colorbar; my_handlecolorbar; my_handle.Label.String depth/km; my_handle.Label.FontSize 15;%% 第二种 figure; A rand(3,4,3); A1 A(:,:,1); A2 …

c# OpenCvSharp透视矫正六步实现透视矫正(八)

透视矫正,引用文档拍照扫描&#xff0c;相片矫正这块。 读取图像Cv2.ImRead();预处理&#xff08;灰度化&#xff0c;高斯滤波、边缘检测&#xff09;轮廓检测&#xff08;获取到最大轮廓&#xff09;获取最大面积轮廓的四个顶点标识最小矩形坐标透视矫正显示 完整代码 // 1、…

【中小型企业网络实战案例 二】配置网络互连互通

​【中小型企业网络实战案例 一】规划、需求和基本配置-CSDN博客 热门IT技术视频教程&#xff1a;https://xmws-it.blog.csdn.net/article/details/134398330?spm1001.2014.3001.5502 配置接入层交换机 1.以接入交换机ACC1为例&#xff0c;创建ACC1的业务VLAN 10和20。 <…

异常和智能指针

智能指针的认识 智能指针是一种C语言中用于管理动态内存的工具&#xff0c;它们可以自动管理内存的分配和释放&#xff0c;从而避免内存泄漏和悬空指针等问题。智能指针可以跟踪指向的对象的引用次数&#xff0c;并在需要时自动释放被引用的内存&#xff0c;这极大地提高了内存…

如何查看NX UI对话框内的控件(使用UIFW侦查)

一、概述 在NX二次开发中有很多命令从界面上看起开相似&#xff0c;但实质确不同&#xff0c;个人人为一是出于对软件产权的保护&#xff0c;增加二次开发的难度&#xff0c;二是由于NX在不断地发展和版本交替中为了保留老用户的操作习惯&#xff0c;故意用新控件做成老控件的…

【我与java的成长记】之面向对象的初步认识

系列文章目录 能看懂文字就能明白系列 C语言笔记传送门 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言一、什么是面向对象面向过程…

与供应商合作:成功供应商管理的六种最佳实践

许多企业低估了他们对外部供应商的依赖程度&#xff0c;也小看了这些供应商关系所涉及的风险。本文将探索企业与外部供应商合作的六种最佳实践&#xff0c;利用它们创建有效的供应商管理流程&#xff0c;从而降低成本和风险&#xff0c;并提高盈利能力。 供应商管理为何重要&a…

【UML】第13篇 序列图(2/2)——建模的方法

目录 三、序列图建模 3.1 概述 3.2 建模的步骤 3.3 举例说明步骤 1.确定主要场景和流程 2.确定参与的对象 3.绘制序列图 4.注意事项 3.4 特殊的情况 序列图是我个人认为&#xff0c;UML中最重要的图之一。 而且序列图&#xff0c;对于业务建模&#xff0c;也有非常好…

SpringBoot + vue3 + TypeScript + activiti7 + 动态表单 的工作流引擎

工作流 SpringBoot vue3 TypeScript activiti7 动态表单 可动态绑定数据库表 的工作流引擎 介绍 兴趣使然&#xff0c;想开发一套自己认为的工作流 项目使用 vue3 elementui-plus ts Activit7 SpringBoot &#xff0c;项目从零搭建 可移植性高&#xff0c;无依赖多余…

C语言学习day10:if语句

程序流程结构&#xff1a; C 语言支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构。 顺序结构:程序按顺序执行&#xff0c;不发生跳转。选择结构:依据是否满足条件&#xff0c;有选择的执行相应功能。循环结构:依据条件是否满足&#xff0c;循环多次执行某段代码…

Ubuntu20.04-查看GPU的使用情况及输出详解

1. 查看GPU的使用情况 1.1 nvidia-smi # 直接在终端得到显卡的使用情况 # 不会自动刷新 nvidia-smi# 重定向到文件中 nvidia-smi > nvidia_smi_output.txt# 如果输出的内容部分是以省略号表示的&#xff0c;可以-q nvidia-smi -q 1.2 nvidia-smi -l # 会自动刷新&#x…

eventbus,在this.$on监听事件时无法在获取数据

问题&#xff1a;vue中eventbus被多次触发&#xff0c;在this.$on监听事件时&#xff0c;内部的this发生改变导致&#xff0c;无法在vue实例中添加数据。 项目场景 一开始的需求是这样的&#xff0c;为了实现两个组件(A.vue ,B.vue)之间的数据传递。 页面A&#xff0c;点击页面…

【论文阅读笔记】SegVol: Universal and Interactive Volumetric Medical Image Segmentation

Du Y, Bai F, Huang T, et al. SegVol: Universal and Interactive Volumetric Medical Image Segmentation[J]. arXiv preprint arXiv:2311.13385, 2023.[代码开源] 【论文概述】 本文思路借鉴于自然图像分割领域的SAM&#xff0c;介绍了一种名为SegVol的先进医学图像分割模型…