(学习笔记-进程管理)进程

news2024/11/24 12:02:58

进程

我们编写的代码只是一个存储在硬盘的静态文件,通过编译后会生成二进制可执行文件,当我们运行这个可执行文件后,它会被装载到内存中,接着CPU会执行程序中的每一条指令,那么这个运行中的程序就被称为进程

现在我们考虑有一个会读取硬盘文件数据的程序执行了,那么当运行到读取文件指令时,就会去从硬盘读取数据,但是硬盘的读写速度相比于CPU的处理速度是非常慢的,那么在这个时候,如果CPU一直等待硬盘返回数据的话,CPU的利用率是非常低的。

类比,当你去烧开水的时候,你不会傻傻等水壶烧开。我们可以在水壶烧开之前去做其他事情。当水壶烧开了,我们自然会听到"滴滴滴"的声音,于是再把烧开的水倒入到水杯中就好了。

所以,当进程要从硬盘读取数据时,CPU不需要阻塞等待数据的返回,而是去执行另外的进程。当硬盘数据返回时,CPU会收到一个中断,于是CPU会再继续运行这个进程。

 这种多个程序、交替执行的思想,就有CPU管理多个进程的初步想法。

对于一个支持多进程的系统,CPU会从一个进程快速切换到另一个进程,期间每个进程各运行几十或几百毫秒。

虽然大单核CPU在某个瞬间,只能运行一个进程。但在一秒钟内,他可能会运行多个进程,这样就产生了并行的错觉,实际上这是并发

并行和并发的区别

 进程与程序的关系

到了晚饭时间,一对小情侣肚子都咕咕叫了,于是男生见机行事,就想给女生做晚饭,所以他就在网上找了辣子鸡的菜谱,接着买了一些鸡肉、辣椒、香料等材料,然后边看边学边做这道菜。

突然,女生说她想喝可乐,那么男生只好把做菜的事情暂停一下,并在手机菜谱标记做到哪一个步骤,把状态信息记录了下来。

 然后男生听从女生的指令,跑去下楼买了一瓶冰可乐后,又回到厨房继续做菜。

这体现了,CPU 可以从一个进程(做菜)切换到另外一个进程(买可乐),在切换前必须要记录当前进程中运行的状态信息,以备下次切换回来的时候可以恢复执行。

所以,可以发现进程有着「运行 - 暂停 - 运行」的活动规律。


进程的状态

我们知道了进程有着 [运行-暂停-运行] 的活动规律。一般来说,一个进程并不是自始至终连续不停地运行的,它与并发执行中的其他进程的执行是相互制约的。

它有时处于运行状态,有时又由于某种原因而暂停运行处于等待状态,当使他暂停的原因消失后,它又进入准备运行状态。

所以,在一个进程的活动期间至少具备三种基本状态,即运行状态、就绪状态、阻塞状态

  • 运行状态:该时刻进程占用CPU
  • 就绪状态:可运行,由于其他进程处于运行状态而暂时停止运行
  • 阻塞状态:该进程正在等待某一事件发生(如等待输入/输出操作完成)而暂停运行,这时,及时给它CPU控制权,它也无法运行。

当然,进程还有另外两个基本状态:

  • 创建状态:进程正在被创建时的状态
  • 结束状态:进程正在从系统中消失时的状态

于是完整的进程状态图为:

  • NULL -> 创建状态:一个新进程被创建时的第一个状态
  • 创建状态 -> 就绪状态:当进程被创建完成并初始化后,一切就绪准备运行时,变成就绪状态,这个过程很快。
  • 就绪状态 -> 运行状态:处于就绪状态的进程被操作系统的进程调度器选中后,就分配给CPU正式运行该进程。
  • 运行状态 -> 结束状态:当进程已经完成或出错时,会被操作系统作结束状态处理
  • 运行状态 -> 就绪状态:处于运行状态的进程在运行过程中,由于分配给它的时间片用完,操作系统会把该进程变为就绪状态,接着从就绪态中选中另外一个进程运行
  • 运行状态 -> 阻塞状态:当进程请求某个事件且必须等待时,例如I/O事件
  • 阻塞状态 -> 就绪状态:当进程要等待的事件完成时,它从阻塞状态变到就绪状态

如果有大量处于阻塞状态的进程,进程可能会占用着物理内存空间。显然不是我们所希望的,因为物理内存空间有限,被阻塞状态的进程占用物理内存就是一种浪费物理内存的行为。

所以,在虚拟内存管理的操作系统中,通常会把阻塞状态的进程的物理内存换出到硬盘,等需要再次运行的时候,再从硬盘换入到物理内存。

那么,就需要一个新的状态,来描述进程没有占用实际的物理内存空间的情况,这个状态就是挂起状态。这跟阻塞状态是不一样的,阻塞状态是等待某个事件的返回。 

挂起状态可以分为两种:

  • 阻塞挂起状态:进程在外存(硬盘),并等待某个事件的出现
  • 就绪挂起状态:进程在外存(硬盘),但只要进入内存,即刻运行。

这两种状态加上前面的五种状态,就变成了七种状态变迁:

导致进程挂起的原因不只是因为进程所使用的内存空间不在物理内存,还包括如下情况:

  • 通过 sleep 让进程间歇性挂起,其工作原理是设置一个定时器,到期后唤醒进程
  • 用户希望挂起一个程序的执行,比如在Linux中用 Ctrl + Z 挂起程序

进程的控制结构

在操作系统中,是用进程控制块(process control block ,PCB) 数据结构来描述进程的。

PCB是进程存在的唯一标识,这意味着一个进程的存在,必然会有一个PCB,如果进程消失了,那么PCB也会随之消失。

PCB具体包含什么信息呢?

进程描述信息:

  • 进程标识符:标识各个进程,每个进程都有一个并且唯一的标识符(通常为进程的序号)
  • 用户标识符:进程归属的用户,用户标识符主要为共享和保护服务

CPU状态信息:

  • 当处理机被中断时,其寄存器中的信息都必须保存在进程的PCB中,以便该进程从新执行时,能从断点继续执行

进程调度信息:

  • 进程状态,如 new、ready、running、waiting和blocked等,作为进程调度和对换的依据
  • 进程优先级:用于描述进程使用CPU的优先级,优先级高的进程应该优先获取CPU
  • 进程调度所需信息:如进程已等待CPU的时间总和,进程已执行的时间总和等
  • 事件:进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因

进程控制信息:

  • 程序和数据的地址(进程的程序和数据所在的内存或外存首地址,以便在调度该进程的时候能从PCB中找到其程序和数据)
  • 进程同步和通信机制(实现进程同步和进程通信时必需的机制,如消息队列指针,信号量等)
  • 资源清单(除CPU外的进程所需的全部资源以及已经分配到该进程的资源的清单)
  • 链接地址(本进程PCB所在队列中的下一个进程的PCB的首地址)

每个PCB是如何组织的?

通常是通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列。比如:

  • 将所有处于就绪状态的进程链在一起,称为就绪队列
  • 把所有因等待某事件而处于等待状态的进程链在一起,组成各种阻塞队列
  • 对于运行队列在单核CPU系统中则就只有一个运行指针了,因为单核CPU在某个时间只能运行一个程序。

那么,就绪队列和阻塞队列链表的组织形式如下:

 除了链接的组织方式,还有索引方式,它的工作原理:将同一状态的进程组织在一个索引表中,索引表项指向相应的PCB,不同状态对应不同的索引表。

一般会选择链表,因为可能面临进程创建,销毁等调度导致进程状态发生变化,所以链表能够更加灵活的插入和删除。


进程的控制

这里我们介绍进程的创建、终止、阻塞、唤醒的过程,这些过程也就是进程的控制

创建进程

操作系统允许一个进程创建另一个进程,而且运行子进程继承父进程所拥有的资源。

创建进程的过程如下:

  • 申请一个空白的PCB,并向PCB中填写一些控制和管理进程的信息,比如进程的唯一标识等
  • 为该进程分配运行时所必需的资源,以及新进程的程序和数据以及用户栈分配必要的内存空间
  • 将PCB插入到就绪队列,等待被调度运行

终止进程

进程可以有3种终止方式:正常结束、异常结束以及外界干预(信号 kill 掉)

当子进程被终止时,其在父进程处继承的资源应当还给父进程。而当父进程被终止时,该父进程的子进程就变为孤儿进程,会被 1 号进程收养,并由 1 号进程对它们完成状态收集工作。

终止进程的过程如下:

  • 根据被终止的进程的标识符,查找需要终止的进程的PCB
  • 如果处于执行状态,则立即终止该进程的执行,然后将CPU资源分配给其他进程
  • 如果其还有子进程,则应将进程的子进程终止,防止它们成为不可控的进程
  • 将该进程所拥有的全部资源或归还于其父进程或都归还给操作系统
  • 将其从 PCB 所在队列中移出,等待其他程序来搜集信息

阻塞进程

引起进程阻塞的与唤醒的事件如下:

  1. 请求系统服务:当正在执行的进程请求操作系统提供服务时,由于某种原因,操作系统并不立即满足该进程的要求,该进程只能被转换为阻塞状态来等待
  2. 启动某种操作:当进程启动某种操作后,如果该进程必须在该操作完成之后才能继续执行,则必须先使该进程阻塞,以等待该操作完成
  3. 新数据尚未到达:对于相互合作的进程,如果其中一个进程需要先获得另一合作进程提供的数据后才能对数据进行处理,则只要其所需数据尚未到达,该进程只有(等待)阻塞
  4. 无新工作可做:系统往往设置了一些具有某些特定功能的系统进程,每当这种进程完成任务后,便把自己阻塞起来等待新任务的到来。

进程阻塞的步骤如下:

  • 找到将要被阻塞进程标识号对应的PCB
  • 如果该进程为运行状态,则保护其现场,将其状态转为阻塞状态,停止运行
  • 将该PCB插入到阻塞队列中去

唤醒进程

进程由 [运行] 转变为 [阻塞] 状态是由于进程必须等待某一事件的完成,所以处于阻塞状态的进程是绝对不可能唤醒自己的。

当被阻塞进程所期待的事件出现时,如I/O完成获其所期待的数据已经到达,则由有关进程(如用完并释放I/O设备的进程)调用唤醒语句wakeup,将等待该事件的进程唤醒,首先将被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中。值得注意的是,block原语与wakeup原因应该在不同进程中执行

唤醒进程的过程如下:

  • 在该事件的阻塞队列中找到相应进程的 PCB
  • 将其从阻塞队列中移出,并置其状态为就绪状态
  • 把该PCB插入到就绪队列中,等待调度程序调度

进程的阻塞和唤醒是一对功能相反的语句,如果某个进程调用了阻塞语句,则必有一个与之对应的唤醒语句。


进程的上下文切换

各个进程之间是共享CPU资源的,在不同的时候进程之间需要切换,让不同的进程可以在CPU执行,那么这个一个进程切换到另一个进程运行,称为进程的上下文切换

CPU的上下文切换

大多数操作系统都是多任务,通常支持大于CPU数量的任务同时运行。实际上,这些任务并不是同时运行的,只是因为系统在很短的时间内让各个任务分别在CPU上运行,于是就造成了同时运行的错觉。

任务是交给CPU运行的,那么在每个任务运行前,CPU需要知道任务从哪里加载,又从哪里开始运行。

所以,操作系统事先需要帮CPU设置好CPU寄存器和程序计数器

CPU寄存器是CPU内部一个容量小,但速度极快的内存(缓存)。

程序计数器则是用来存储CPU正在执行的指令位置,或者即将执行的下一条指令位置。

所以,CPU寄存器和程序计数器是CPU在运行任何任务前,所必须依赖的环境,这些环境就叫做CPU上下文

CPU上下文切换就是把前一个任务的上下文(CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

系统内核会存储保存下来的上下文信息,当此任务再次被分配给CPU运行时,CPU会重新加载这些上下文,这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。

上面说到所谓的 [任务],主要包含进程、线程和中断。所以,可以根据任务的不同,把CPU上下文切换分为:进程上下文切换、线程上下文切换和中断上下文切换

进程的上下文切换到底是切换什么呢?

进程是由内核管理和调度的,所以进程的切换只能发生在内核态

所以,进程的上下文切换不仅包含了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的资源

通常,会把交换的信息保存在进程的 PCB,当要运行另外一个进程的时候,我们需要从这个进程的 PCB 取出上下文,然后恢复到 CPU 中,这使得这个进程可以继续执行,如下图所示:

 需要注意,进程的上下文开销是很关键的,我们希望它的开销越小越好,这样可以使得进程可以把更多时间花费在执行程序上,而不是耗费在上下文切换。

发生进程上下文切换有哪些场景?

  • 为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,进程就从运行状态变为就绪状态,系统从就绪队列选择另外一个进程运行;
  • 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行;
  • 当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度;
  • 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行;
  • 发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序;

以上,就是发生进程上下文切换的常见场景了。

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

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

相关文章

怎么加密文件夹才更安全?安全文件夹加密软件推荐

文件夹加密可以让其中数据更加安全,但并非所有加密方式都能够提高极高的安全强度。那么,怎么加密文件夹才更安全呢?下面我们就来了解一下那些安全的文件夹加密软件。 文件夹加密超级大师 如果要评选最安全的文件夹加密软件,那么文…

python GUI nicegui初识一(登录界面创建)

最近尝试了python的nicegui库,虽然可能也有一些不足,但个人感觉对于想要开发不过对ui设计感到很麻烦的人来说是很友好的了,毕竟nicegui可以利用TailwindCSS和Quasar进行ui开发,并且也支持定制自己的css样式。 这里记录一下自己利…

spring security + oauth2 使用RedisTokenStore 以json格式存储

1.项目架构 2.自己对 TokenStore 的 redis实现 package com.enterprise.auth.config;import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis…

leetcode刷题:1657. 确定两个字符串是否接近、1004. 最大连续1的个数 III

leetcode刷题:1657. 确定两个字符串是否接近、1004. 最大连续1的个数 III 1. 前言2. 1657. 确定两个字符串是否接近3. 1004. 最大连续1的个数 III4. 总结 1. 前言 上述两个题目位于leetcode75中,难度为中等,虽然对于大佬而言,可能很简单&…

2023年C++面试宝典

目录 第一章:C基础知识1.1 C语言起源与发展1.2 C的重要特点和优点1.3 C的数据类型和变量1.4 函数和命名空间1.5 运算符和表达式 第二章:面向对象编程2.1 类与对象的概念2.2 封装、继承和多态2.3 构造函数和析构函数2.4 静态成员和常量成员2.5 虚函数和纯…

maven install命令:将包安装在本地仓库,供本地的其它工程或者模块依赖

说明 有时候,自己本地的maven工程依赖于本地的其它工程,或者manven工程中的一个模块依赖于另外的模块,可以执行maven的install命令,将被依赖的包安装在maven本地仓库。 示例 一个工程包含几个模块,模块之间存在依赖…

【笔记】第94期-冯永吉-《湖仓集一体关键技术解读》-大数据百家讲坛-厦大数据库实验室主办20221022

https://www.bilibili.com/video/BV1714y1j7AU/?spm_id_from333.337.search-card.all.click&vd_sourcefa36a95b3c3fa4f32dd400f8cabddeaf

VSCode配置SSH远程免密登录服务器

VScode远程开发时,每次都需要输入密码,其实同理可以和其他应用类似配置免密登录,流程也类似。 1.在本地主机生成公钥和秘钥 ssh-keygen 2.将公钥内容添加至服务器 将生成钥对时会给出其保存路径,找到公钥,复制内容&am…

废弃的 电信光猫 改为 免费的wifi

修改为桥接模式即可。 1.修改电脑IP地址与光猫同一网段,例如192.168.1.2 掩码255.255.255.0。 电信光猫默认地址为 192.168.1.1 掩码为 255.255.255.0 2.网线或者无线连接光猫,无线wifi 名称(SSID)和密码 光猫背后都有。 3.浏…

事务到底是隔离的还是不隔离的 (具体)

遇到不明白的慢慢往后读,一下你就明白了。 下面是一个只有两行的表的初始化语句 mysql> CREATE TABLE t ( id int(11) NOT NULL, k int(11) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB; insert into t(id, k) values(1,1),(2,2); 这里,我们需要注…

ADS版图画封装联合仿真学习视频

ADS版图画封装 因为晶体管ATF54143在ADS中是没有封装的,所以要在ADS中画ATF54143的封装,操作步骤如下: 在ADS中新建layout,命名为ATF54143_layout, 根据datasheet知道封装的大小,进行绘制 在layout的con…

GO语言基础语法探究:简洁高效的编程之道

文章目录 前言Go词法单元token标识符关键字( 25个 )内置数据类型标识符( 20个 )内置函数( 15个 )常量值标识符( 4个)空白标识符( 1个 ) 操作符和分隔符字面常…

通向架构师的道路之基于数据库的权限系统的设计

一、权限系统 这一天将讲述一个基本的基于数据库的权限管理系统的设计,在这一天的课程的最后将讲述“左右值无限分类实现算法”如何来优化“系统菜单”的结构而告终。今天的内容和前几天的基础框架是一样的它们都属于基础知识,在这些基础知识上还可以扩…

Leetcode 剑指 Offer II 038. 每日温度

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 请根据每日 气温 列表 temperatures ,重新生成一个列…

第5集丨Vue 江湖 —— 监视属性/侦听属性

目录 一、基本使用1.1 watch配置监视1.2 vm.$watch动态监视1.3 深度监视(deep watch)1.4 简写形式 二、computed和watch的对比2.1 使用watch实现setTimeout操作2.2 用computed无法实现setTimeout 三、其他注意事项3.1 vue devtools的bug3.2 xxxyyy格式3.3 将window传入data中 V…

高并发负载均衡---LVS

目录 前言 一:负载均衡概述 二:为啥负载均衡服务器这么快呢? ​编辑 2.1 七层应用程序慢的原因 2.2 四层负载均衡器LVS快的原因 三:LVS负载均衡器的三种模式 3.1 NAT模式 3.1.1 什么是NAT模式 3.1.2 NAT模式实现LVS的缺点…

c++--二叉树应用

1.根据二叉树创建字符串 力扣 给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。 空节点使用一对空括号对 "()" 表示,转化后需要省略所有不影响字符…

【react】react中BrowserRouter和HashRouter的区别:

文章目录 1.底层原理不一样:2.path衣现形式不一样3.刷新后对路山state参数的影响4.备注: HashRouter可以用于解决一些路径错误相关的问题 1.底层原理不一样: BrowserRouter使用的是H5的history API,不兼容IE9及以下版不。 HashRouter使用的是URL的哈希值。 2.path衣…

Element-ui中分页器的使用

<template>中写&#xff1a; js中写&#xff1a;

pytorch的CrossEntropyLoss交叉熵损失函数默认reduction是平均值

pytorch中使用nn.CrossEntropyLoss()创建出来的交叉熵损失函数计算损失默认是求平均值的&#xff0c;即多个样本输入后获取的是一个均值标量&#xff0c;而不是样本大小的向量。 net nn.Linear(4, 2) loss nn.CrossEntropyLoss() X torch.rand(10, 4) y torch.ones(10, dt…