进程状态+进程优先级+进程上下文切换解读

一、进程状态

什么是进程状态?

进程状态指的是在操作系统中进程在生命周期中所处的不同阶段。

进程状态有哪些呢?
在这里插入图片描述

我们可以看到上述图片
进程状态分为:创建状态、就绪状态、运行状态、阻塞状态和终止状态

所有的操作系统在实现进程状态变化的时候都要符合上面的理论。
进程在运行的时候是需要资源的,也就是说进程之间是有竞争的,它们竞争的资源分为两类:外设资源和CPU资源(输入输出设备统称为外设资源,运算器和控制器统称为CPU资源)

大部分的操作系统内部都要给每个CPU设置一个调度队列多个CPU就要多个调度队列,操作系统对调度队列进行的管理方式就是先描述在组织

综上所述,我们就知道了在操作系统中就要有一个struct runqueue

struct runqueue
{//队列属性int num; //队列个数struct task_stuct* head;
}

所以说CPU的调度队列是怎么样拿到该进程的呢?

struct task_struct
{//所有的属性struct list_head tasks;
}
struct list_head
{struct list_head* next;struct list_head* prev;
}

看上述的代码,在struct task_struct里面有一个struct list_head tasks的变量,struct list_head里面包含两个指针分别是next和prev指针,它是通过struct list_head来实现双链表的。所以综上所述我们就可以知道,只要我们得到struct task_struct结构体中的struct list_head tasks变量的地址,我们就可以利用偏移量来得到task_struct的起始地址。

既然我们知道task_struct的起始地址 = struct list_head变量的地址 - 偏移量了,那偏移量该怎么得到呢?

假设在地址为0处有一个struct task_struct变量,去访问该变量中的struct list_head变量并进行取地址:&((struct task_struct*)0->tasks)。我们要知道的是,对于每一个进程来书,struct task_struct结构体的大小是固定的,所以说struct list_head在struct task_struct中的偏移量也是固定的。那么struct task_struct* start = &stract list_head task - &((struct task_struct*)0->tasks).

所以说在linux中PCB实现双链表的这种方式就再也和类型没有关系了,struct task_struct既可以属于链表,同时也可以属于其他数据结构。

在linux中是没有就绪状态的,所以我们认为就绪状态和运行状态不分家。在有些系统中,认为PCB处在运行队列中但是未分配CPU资源叫做就绪状态,正在CPU中执行的进程叫做运行状态。

每个进程都要竞争CPU资源,所以就得把进程链入到调度队列中。我们把上述这个行为叫做进程在CPU的调度队列当中进行排队。进行排队时,该进程的状态就叫做(r)运行状态

运行状态:该进程的PCB必须处在CPU的调度队列中,只要在调度队列中,进程就叫做运行状态,随时等待CPU的调度执行

阻塞状态:当进程无法继续执行,需要等待某些非CPU资源就绪时,就会进入阻塞状态(进程进入阻塞状态,PCB会被移除运行队列,进入等待队列)

挂起状态:当内存空间严重不足时,操作系统会将进程的代码,数据,堆栈等内存资源移出内存,换出磁盘的交换区里,但进程的PCB仍然保留在内存中,这就叫挂起状态

新建状态:操作系统为进程分配必要的资源,并为进程分配唯一的标识符

下面的状态在kernel源代码里定义:

/*
*The task state array is a strange "bitmap" of
*reasons to sleep. Thus "running" is zero, and
*you can test for combinations of others with
*simple bit tests.
*/
static const char *const task_state_array[] = {
"R (running)", /*0 */
"S (sleeping)", /*1 */
"D (disk sleep)", /*2 */
"T (stopped)", /*4 */
"t (tracing stop)", /*8 */
"X (dead)", /*16 */
"Z (zombie)", /*32 */
};

R运行状态(running): 并不意味着进程⼀定在运行中,它表明进程要么是在运行中要么在运行队列⾥。
• S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
• D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
• T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
• X死亡状态(dead):这个状态只是⼀个返回状态,你不会在任务列表⾥看到这个状态。

看下面这个代码,代码运行时我们发现它的状态怎么会是S(睡眠状态)状态呢?不应该是R(运行状态)吗?
在这里插入图片描述
在这里插入图片描述
接下来我们再改一下代码在这里插入图片描述
很奇怪的就是为什么将while中的printf屏蔽了就变成了R状态呢?

在这里插入图片描述
原因就是printf是向显示器打印内容的,访问的是外设资源,外设的速度很慢,很大概率是无法就绪的,所以就是S状态。但是有少数的概率会显示R状态

其实S这个状态是一种浅度睡眠的状态,我们可以使用ctrl+c来杀掉浅度睡眠,而D这种状态则是深度睡眠,其不对任何事件进行响应,连操作系统都不能杀掉,除非是说进程自己醒过来。

僵尸进程

模拟实现僵尸进程
在这里插入图片描述
运行代码得到的结果如下:

在这里插入图片描述
在这里插入图片描述
我们看上述代码会发现子进程比父进程先退出,父进程就会先处于一个僵尸状态代码、数据释放掉,但是会保留struct task_struct,PCB会自动记录进程退出时的退出信息,方便父进程读取退出码。

假设父进程一直不处理,一直处于僵尸进程,PCB一直存在于内存中,这就会导致内存的泄露。

那如果我们是父进程先退出呢?子进程会怎么样?

孤儿进程

模拟实现孤儿进程
在这里插入图片描述
运行结果如下:
在这里插入图片描述
在这里插入图片描述
我们查看进程状态发现一个很奇怪的东西,就是这个1号进程是什么呢?

子进程被操作系统一号领养了,一号是一个叫做init的进程

在linu中init进程是什么?

它是系统启动后运行的第一个用户态进程,通常具有进程 ID(PID)为 1。init 进程的主要作用是初始化系统环境、启动其他关键服务和守护进程,并管理系统的运行级别。

为什么要领养子进程呢?

因为孤儿进程也会退出,但是父进程早早就没了,所以会被系统领养,本质上是为了回收孤儿进程防止内存泄漏。

进程退出不应该会变成僵尸进程吗?为什么没有看到父进程的僵尸状态呢?

子进程的父进程的父进程是bash(外壳程序),父进程一旦退出,就会被bash回收,所以看不到父进程的僵尸状态,具体过程看下面两张图。

在这里插入图片描述

在这里插入图片描述

二、进程的优先级

什么是进程的优先级?

在操作系统中,进程的优先级是用于决定进程调度顺序的一个重要参数。优先级越高,进程获得 CPU 时间片的机会就越大。总而言之就是进程得到某种资源的先后顺序

在这里插入图片描述
我们使用ps -al命令查看进程的优先级

UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值

PRI越小代表该进程优先级越高,它就是一个整数,存在于task_struct中,而NI是一个修正数据:PRI(new) = PRI(old) + nice 在linux中nice的取值范围是-20~19,一共40个级别。

使用top来改变PRI,步骤如下:

top指令后,-r进入pid,接着输入pid
在这里插入图片描述
在这里插入图片描述

补充进程的性质:

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

三、进程切换

在这里插入图片描述
CPU内有很多寄存器,这些寄存器就是一套储存空间,寄存器只有一套,属于CPU本身,但是寄存器内部的数据可以有很多。进程在被切换的时候,进程PCB会保存该进程的上下文数据,以便进程再被调度的时候可以恢复数据。

看上述图片中红色括号中的queue数组,这个是什么呢?

其实queue数组类型是一个struct list_head类型,简单的理解就是认为它是一个struct task_struct*类型,它可以使用struct list_head中的节点指针对进程进行关联,这个进程的大小是140,下标[0,99]我们不需要理会,[100,139]刚好是40个,然而我们进程范围是[60,99]刚刚好也是40个,所以我们知道操作系统根据进程的优先级将进程挂接在对应的下标上。

在linux中对进程调度的时候,用到一个bitmap[5],利用位图的方式对queue数组进行遍历,这样能提高效率。但是为什么是5呢?因为一个整型4个byte,32个bit,那么5个就是160个bit,刚刚好对应下标140.

对应的比特位的位置表示的是数组中第几个队列比特位的内容表示的是队列是否为空。

我们再看向上面的图片会发现有两个指针分别是:struct prio_array*,struct prio_array* expired,这两个指针分别是活跃队列过期队列
CPU调度的时候直接从
active指针找到对应的queue[140],新增进程或者时间片到的进程,从CPU上剥离下来,被剥离下来的进程只能重新入队列,入过期队列。

既然如此为什么要有nice值呢?

如果我们要改PRI值的时候,我们能直接改吗?答案是不能的,因为我们直接改PRI值那么进程就会被立即迁移到对应的队列上,而有了nice值的话就不会影响active队列中进程的调度,在expired队列中对应的进程的优先级做出调整。

等到CPU调度完所有进程,所有进程都会跑到过期队列。一旦active没有进程了,这时只需要交换active,expired指针内容就可以了。

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

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

相关文章

Android 原生与 Flutter 通信完整实现 (Kotlin 版)

1. 项目配置 pubspec.yaml 添加依赖 dependencies:flutter:sdk: flutterprovider: ^6.0.52. Flutter 端实现 状态管理类 // settings_provider.dart import package:flutter/foundation.dart;class SettingsProvider with ChangeNotifier {String _themeColor blue;bool _dark…

数字图像处理3

图像线性滤波——目的就是滤去噪声,但是边缘会模糊,整体也模糊线性:邻域平均法(4邻域平均和8邻域平均)用当前运算点所在邻域的平均值来代替该点的平均值im_for_read"D:\AAAproject\PYproject\EXPERuse\zaosheng.j…

Linux发行版分类与Centos替代品

让centos7气的不轻,这玩意儿太老了,什么都不好配置。 目录Linux 发行版的大致分类1. Red Hat 系列(RPM 系)2. Debian 系列(DEB 系)3. Arch 系列4. SUSE 系列CentOS 7 的替代品推荐AlmaLinux 和 Rocky Linux…

大语言模型提示工程与应用:大语言模型对抗性提示安全防御指南

对抗性提示工程 学习目标 理解大语言模型中对抗性提示的风险与防御机制,掌握提示注入、提示泄露和越狱攻击的检测方法,培养安全防护意识。 相关知识点 对抗性攻击类型防御技术 学习内容 1 对抗性攻击类型 1.1 提示注入 提示注入旨在通过使用巧妙…

避不开的数据拷贝(2)

接着上周未完的话题 避不开的数据拷贝。 既然处理器是通用机器,就没有专属数据,所以数据都要从别处调来,这就涉及到了数据搬运,就有了外设的概念。由于不同外设和处理器一起共享数据存储,时间会花在两方面&#xff1a…

娃哈哈经销商“大洗牌”:砍掉年销300万以下经销商

文 | 大力财经据第一财经报道,娃哈哈在宗馥莉“铁腕”策略推动下,正经历经销商体系的重大变革,陆续砍掉年销低于300万元的经销商,方式有时颇为激进,“一刀切”的做法引发诸多争议,部分经销商反馈存在款项未…

drippingblues靶机通关练习笔记

前言 将靶机导入到vmware虚拟机上 靶机下载地址:https://download.vulnhub.com/drippingblues/drippingblues.ova 将网段都设置为nat 信息收集 ip端口扫描 netdiscover -r 192.168.25.1/24 --确定ip nmap -A -p- 192.168.25. kalid的ip:1…

QT第三讲- 机制、宏、类库模块

文章目录 🧩 一、Qt核心机制与类库 🔧 1. 元对象系统(Meta-Object System) ⚡ 2. 信号与槽(Signals & Slots) • 通信机制 📦 3. 属性系统(Property System) 动态属性 例程 类的附加信息 Q_CLASSINFO 例程 🌐 二、全局定义与容器 📝 1. 全局数据类型与函数…

(LeetCode 每日一题) 869. 重新排序得到 2 的幂 (哈希表+枚举)

题目&#xff1a;869. 重新排序得到 2 的幂 思路&#xff1a;哈希表枚举。先预处理出所有的2的幂数&#xff0c;用哈希表来存储。 C版本&#xff1a; class Solution { public:// 哈希表存储所有 2的幂数 按升序排列的形式unordered_set<string> st;// 预处理出所有的2…

WebAssembly技术详解:从浏览器到云原生的高性能革命

引言&#xff1a;WebAssembly的诞生与使命 2015年&#xff0c;当Mozilla、Google、Microsoft和Apple四大浏览器厂商联合发布WebAssembly&#xff08;Wasm&#xff09;技术预览时&#xff0c;业界尚未意识到这将开启Web性能的新纪元。作为继HTML、CSS、JavaScript之后的第四种We…

性能解析案例

异步io是内核fd与应用程序直接的关系io 多路复用1.检测io是否就绪2.read/write消息队列kafka&#xff1a;1.典型应用 &#xff1a;异步处理&#xff0c;系统解耦&#xff0c;流量削峰&#xff0c;日志处理2.核心原理&#xff1a;kafka体系结构以及读写流程3.具体操作&#xff1…

青龙峡拔韭菜

我们一年四季&#xff0c;除了冬天不往山里进&#xff0c;其余季节&#xff0c;只要天气允许&#xff0c;我们都会进山。在山里拔韭菜&#xff0c;是我们百做不烦的一件事。今年大旱&#xff0c;从五月份上山找韭菜&#xff0c;没有如愿。直到入秋后&#xff0c;我们再次去青龙…

5、docker镜像管理命令

1、命令总览命令&#xff08;含关键参数&#xff09;作用出现频率备注docker buildx build --platform … -t … --push .一次构建并推送多平台镜像高频需先 docker buildx create --usedocker buildx build -o typedocker,destxxx.tar .构建后离线导出 tar 包中频只导出单平台…

阿里云ECS云服务器临时升级带宽方法

阿里云ECS云服务器临时升级带宽方法一、背景与需求二、原理三、操作步骤步骤 0: 准备工作步骤 1: 创建弹性网卡 (ENI)步骤 2: 创建并绑定弹性公网IP (EIP)步骤 3: SSH登录ECS并切换到高速通道 (eth1)步骤 4: 执行你的高带宽任务步骤 5: 任务完成&#xff0c;切回默认网卡 (eth0…

Java语言简介

一.Java语言的起源 Java语言的前身是Oka语言,是美国Sun Microsystems公司于1991年推出的,仅限于公司内部使用的语言。1995年,Sun公司将Oak语言更名为Java语言,并正式向公众推出。这之后,Java语言不断更新,其类库越来越丰富,性能逐步提升,应用领域也显著拓展,已成为当今…

VUE+SPRINGBOOT从0-1打造前后端-前后台系统-视频列表与视频播放

在现代Web开发中&#xff0c;视频播放功能已成为许多网站的基本需求。本文将基于Vue.js框架&#xff0c;详细讲解如何实现一个视频列表与播放器交互的功能模块。这个组件可以让用户点击列表中的视频项来播放对应的视频&#xff0c;并支持再次点击关闭播放器。功能概述我们实现的…

详解 Seaborn:让数据可视化更简单高效的 Python 库

在数据科学领域&#xff0c;可视化是理解数据、挖掘规律的重要手段。今天要为大家介绍的 Seaborn 库&#xff0c;正是数据可视化领域的一把 “利器”。它基于 Matplotlib 开发&#xff0c;却凭借更简洁的接口和更美观的默认样式&#xff0c;成为众多数据分析师的首选工具。下面…

Cesium1.95中如何高效管理 1500 个高频实体

一、建议&#xff1a;不要频繁创建/销毁&#xff0c;而是复用对象&#xff1b;​​​​使用 CallbackProperty更新位置而不是删了重建&#xff1b;​​​​对大量 Billboard / Polyline / Label&#xff0c;优先使用对应的 *Collection&#xff0c;然后批量更新&#xff1b;​​…

全面了解机器语言之kmeans

深入理解 KMeans 聚类算法&#xff1a;原理、实现与应用在机器学习领域&#xff0c;聚类算法作为无监督学习的核心技术之一&#xff0c;一直以来都是数据挖掘和模式识别的重要工具。其中&#xff0c;KMeans 算法以其简洁的原理、高效的计算性能和广泛的适用性&#xff0c;成为最…

纳米陶瓷与光子集成:猎板PCB定义下一代VR硬件的技术蓝图

虚拟现实&#xff08;VR&#xff09;设备正从“视觉沉浸”向“多感官无感交互”演进&#xff0c;其底层PCB技术面临带宽、算力密度与动态可靠性的三重挑战。作为国内高端PCB技术的引领者&#xff0c;​​猎板PCB​​以材料革新、光电子融合与智能响应为核心&#xff0c;构建了适…