【操作系统】考研真题攻克与重点知识点剖析 - 第 2 篇:进程与线程

前言

  • 本文基础知识部分来自于b站:分享笔记的好人儿的思维导图与王道考研课程,感谢大佬的开源精神,习题来自老师划的重点以及考研真题。
  • 此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析,本人技术有限,最终数据清洗结果不够理想,相关CSDN文章便没有发出。

请注意,本文中的部分内容来自网络搜集和个人实践,如有任何错误,请随时向我们提出批评和指正。本文仅供学习和交流使用,不涉及任何商业目的。如果因本文内容引发版权或侵权问题,请通过私信告知我们,我们将立即予以删除。

文章目录

  • 前言
    • 概念引出(王道)
      • 进程的概念
      • 进程的组成——PCB
      • 知识滚雪球:程序是如何运行的?
      • 进程的组成
      • 进程的特征
    • 思维导图
    • 概念引出(哈工大)
      • 首先操作系统要管理CPU
      • 进程
        • 概念
        • 进程实体(进程映象)
        • 进程控制块(PCB)
      • 多进程图像(操作系统核心)
        • 概念
        • 多进程图像从启动开始到关机结束
      • 多进程如何组织(PCB+状态+队列)
        • 进程状态图
        • 进程的组织
      • 进程状态思维导图
      • 多进程如何交替(队列操作+调度+切换)
      • 多进程如何影响(地址映射,内存管理章节介绍)
      • 多进程如何合作(核心在同步,合理的推进顺序)
    • 进程
      • 进程控制
        • 如何实现进程控制?
        • 如何实现原语的“原子性”?
        • 进程的创建(创建原语)
        • 进程的终止(撤销原语)
        • 进程的组赛和唤醒
        • 进程切换(运行态<-->就绪态,内核态下完成)
      • 进程控制思维导图
      • 进程通信
        • 为什么进程通信需要操作系统支持?
        • 共享存储
        • 消息传递
        • 管道通信(一种特殊共享文件,缓冲区)
      • 进程通信思维导图
    • 线程
      • 什么是线程,为什么要引入线程?
      • 属性
      • 概念
      • 线程控制块TCB
      • 线程的状态与转换
      • 实现方式
      • 多线程模型
      • 线程思维导图
      • 调度器/调度程序(scheduler)
      • 闲逛进程
    • 处理机调度
      • 调度
        • 调度的层次
        • 三层调度的联系、对比
        • 调度的时机
        • 进程调度方式
        • 进程的切换与过程
        • 进程调度思维导图
        • 调度的参考(调度算法评价指标)
        • 调度算法的评价指标思维导图
      • 进程的挂起态与七状态模型
      • 处理机调度思维导图
      • 经典调度算法
        • 先来先服务算法 FCFS
        • 短作业优先算法 SJF
      • 对FCFS和SJF两种算法的思考..
        • 高响应比调度算法 HRRN
      • 三种算法总结
        • 时间片轮转算法 RR
        • 优先级调度算法
      • 思考
        • 多级反馈队列调度算法
      • 三种算法总结
        • 多级队列调度算法
    • 进程同步与互斥
      • 基本概念
        • 临界资源
        • 同步
        • 互斥
      • 同步、互斥思维导图
      • 实现临界区互斥的基本方法
        • 软件实现方法
        • 进程互斥的软件实现方法思维导图
        • 硬件实现方法
      • 进程互斥:锁
      • 信号量
      • 信号量机制思维导图
      • 管程(类似于类)
        • 拓展
      • 管程思维导图
      • 经典同步问题
      • 信号量机制思维导图
    • 死锁
      • 死锁的概念
        • 死锁产生的原因
      • 死锁的概念思维导图
      • 死锁的处理策略
        • 死锁预防
          • 预防死锁思维导图
        • 死锁避免
          • 银行家算法总结
        • 死锁的检测和解除
          • 死锁的检测和解除思维导图
      • 死锁、饥饿、死循环的区别
    • 408 - 2023
      • 26. 导致CPU从内核态转为用户态的操作
      • 27. 导致线程由执行态变为就绪态的事件或操作
      • 29. 进程调度和平均周转时间
    • 408-2022
      • 25. 进程调度次数
      • 26. 安全序列的个数
      • 28. 进程状态的转换
    • 408-2021
      • 24. 创建新进程时必须完成的操作
      • 25. 分时系统实现时间片轮转调度所需的数据结构或程序
      • 27. 引起进程调度程序执行的事件
      • 31. 避免系统发生死锁所需的临界资源总数
    • 未完待续,逐张试卷整理中,会一直更新到2009

概念引出(王道)

进程的概念

在这里插入图片描述

进程的组成——PCB

在这里插入图片描述

在这里插入图片描述

知识滚雪球:程序是如何运行的?

在这里插入图片描述

进程的组成

在这里插入图片描述

进程的特征

在这里插入图片描述

思维导图

在这里插入图片描述

概念引出(哈工大)

首先操作系统要管理CPU

  • I/O指令与计算指令运行时间差距极大,只执行一个程序CPU利用率低,为了使CPU忙碌起来、利用率提高

    • 多道程序、交替执行(管理CPU核心,多进程图像)

      • 因为需要切换程序,需要记录执行的程序,引入概念进程(与静态程序区分)

进程

概念
  • 程序一次执行过程,一次程序及其数据在处理机上顺序执行时所发生的活动

  • 资源分配和调度的独立单位(未引入线程)

进程实体(进程映象)
  • PCB

    • 进程描述信息

      • 进程标识符(标志进程)、用户标识符(标识归属用户,为共享和保护服务)
    • 进程控制和管理信息

      • 进程当前状态、进程优先级、代码运行入口地址、程序的外存地址、进入内存时间、处理机占用时间、信号量的使用
    • 资源分配清单

      • 说明有关内存地址空间或虚拟地址空间状况,所打开的文件列表和所使用的输入/输出设备信息

      • 代码段指针、数据段指针、堆栈段指针、文件描述符、键盘、鼠标

    • 处理机相关信息

      • 处理机中各寄存器的值(代码段指针、数据段指针、堆栈段指针、文件描述符、键盘、鼠标)
  • 程序段

    • 概念

      • 能被进程调度程序调度到CPU执行的程序代码段(指令序列)
    • 共享正文段

      • 常量 + 代码
  • 数据段

    • 概念

      • 进程对应的程序加工处理的原始数据或者程序执行时产生的中间和最终结果
    • 数据堆段

      • 动态分配变量 new malloc()
    • 数据栈段

      • 未赋值变量/函数实参
    • 全局区(静态区)

      • 全局变量/静态变量
进程控制块(PCB)
  • 描述进程的基本情况和运行状态,进而控制和管理进程

    • 进程存在的唯一标志

多进程图像(操作系统核心)

概念
  • 用户只关系多个进程运行的样子,操作系统负责将多个进程向前推进
多进程图像从启动开始到关机结束
  • 在这里插入图片描述

    • 操作系统创建1号进程(shell/Windows桌面),用户执行任务也是创建进程(通过1号进程)

    • 用户使用计算机就是启动了一堆进程,操作系统管理计算机就是管理一堆进程

多进程如何组织(PCB+状态+队列)

进程状态图
  • 在这里插入图片描述

    • 创建态:进程正在被创建,未进入就绪态

    • 就绪态:进程已处于准备运行状态
      在这里插入图片描述

    • 运行态:进程在处理机上运行
      在这里插入图片描述

    • 阻塞态(等待态):进程正在等待某个资源而暂停运行
      在这里插入图片描述
      在这里插入图片描述

    • 结束态:进程正从系统消失(正常结束/异常终止)在这里插入图片描述

在这里插入图片描述

进程的组织
  • 队列

    • 在这里插入图片描述

      • 进程以队列形式组织
  • 少数使用索引
    在这里插入图片描述

进程状态思维导图

在这里插入图片描述

多进程如何交替(队列操作+调度+切换)

  • 队列操作

  • 调度(本章下文介绍)

    • 核心是折中,需要考虑具体任务需求,平衡周转时间和响应时间

多进程如何影响(地址映射,内存管理章节介绍)

  • 共享内存

  • 映射表(逻辑地址与物理地址)

多进程如何合作(核心在同步,合理的推进顺序)

  • 本章下文介绍

进程

进程控制

如何实现进程控制?

在这里插入图片描述
在这里插入图片描述

如何实现原语的“原子性”?

在这里插入图片描述

进程的创建(创建原语)
  • 引起创建的事件

    • 用户登录

    • 作业调度

    • 提供服务

    • 应用请求

  • 原语执行过程

    • 分配进程标识号,申请PCB(PCB有限)

    • 为进程分配资源,为程序和数据以及用户栈分配必要的内存空间

    • 初始化PCB,包括初始化标志信息、初始化处理机状态信息、初始化处理机控制信息、设置进程优先级

    • 若进程就绪队列可以接纳新进程,进程就进入就绪态
      在这里插入图片描述

进程的终止(撤销原语)
  • 引起终止的事件

    • 正常结束

    • 异常结束

    • 外界干预

  • 原语执行过程

    • 根据被终止进程的标识符,检索PCB,读取进程状态

    • 若进程处于运行态,终止运行,剥夺处理机

    • 终止进程之下的子进程,该进程所有资源还给父进程或操作系统

    • PCB从队列中删除

在这里插入图片描述

进程的组赛和唤醒
  • 阻塞(自我阻塞)

    • 引起

      • 需要等待系统分配资源

      • 需要等待相互合作的进程完成工作

    • 原语执行过程

      • 找到要被阻塞进程标识号对应PCB

      • 若该进程处于运行态,保护现场,状态转为阻塞态停止运行

      • 将PCB插入对应等待队列

  • 唤醒(其他进程唤醒)

    • 引起

      • 等待事件发生
    • 原语执行过程

      • 找到等待队列中进程相应的PCB

      • 将其从等待队列中移出,状态置为就绪态

      • 将PCB插入就绪队列,等待调度程序调度
        在这里插入图片描述

进程切换(运行态<–>就绪态,内核态下完成)
  • 引起

    • 时间片到

    • 更高优先级到达

    • 进程主动阻塞

    • 当前进程终止

  • 原语执行过程

    • 保存处理机上下文,包括程序计数器和其他寄存器

    • 更新PCB信息

    • 把进程的PCB移入相应队列(就绪/阻塞队列)

    • 选择另一个进程执行,更新其PCB,更新内存管理的数据结构

    • 恢复处理机上下文
      在这里插入图片描述

进程控制思维导图

在这里插入图片描述

进程通信

为什么进程通信需要操作系统支持?

在这里插入图片描述

共享存储
  • 概念(进程<—>共享空间<—>进程)

    • 通信进程间存在直接访问共享空间,实现信息交换
  • 操作系统只负责为通信进程提供可共享使用的存储空间和同步互斥工具,数据交换由用户安排读写指令完成

    • 低级方式:基于数据结构共享

    • 高级方式:基于存储区共享
      在这里插入图片描述

消息传递
  • 概念

    • 以格式化的消息为单位进行数据交换,通过系统提供的发送消息和接收消息原语实现
  • 直接通信方式

    • 发送进程将消息挂在接受进程的消息缓冲队列上在这里插入图片描述
  • 间接通信方式

    • 发送进程把消息发送给某一个中间实体,接收进程从中间实体中获得消息(电子邮件系统)
      在这里插入图片描述
管道通信(一种特殊共享文件,缓冲区)
  • 发送进程以字符流形式将大量数据写入管道,接收进程取

    • 当管道写满时,写进程阻塞,等待读进程将数据取走
  • 管道半双工通信,不可同时读写(全双工通信则双管道)

    • 管道变空后,读进程阻塞
      在这里插入图片描述

在这里插入图片描述

进程通信思维导图

线程

什么是线程,为什么要引入线程?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

属性

在这里插入图片描述

概念

  • 为减少程序在并发执行中的切换开销,引入线程概念(切线程不切进程则资源不用切换)

  • 在这里插入图片描述

    • 进程 = 资源 + 执行执行序列(将资源和指令执行分开)

    • 线程

      • 进程内(在一个资源下)启动多个轻巧的、可以来回切换的指令序列

      • 保留了并发的优点,避免了进程切换的代价

    • 此处李治军老师进程切换的内容,分离为线程的指令的切换与映射表上资源的切换两部分讲,讲解内存管理的时候再讲资源问题,两者分离讲解,进程切换问题迎刃而解

  • 调度

    • 引入线程前

      • 进程是资源和独立调度的基本单位
    • 引入线程后

      • 线程是独立调度的基本单位,进程是资源的基本单元

        • 进程仅为系统资源分配单元,线程处理机分配单元(服务单元)
  • 进程的地址空间相互独立,统一进程的各线程之间共享进程的资源,某进程的线程对其他进程不可见

线程控制块TCB

  • 线程标识符、线程运行状态、优先级

  • 线程切换保存/恢复

    • 程序计数器PC、其他寄存器、堆栈指针
      在这里插入图片描述

线程的状态与转换

在这里插入图片描述

实现方式

  • 用户级线程

    • 有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在

      在这里插入图片描述
      在这里插入图片描述
  • 内核级线程

    • 线程的管理工作全部由内核完成
  • 用户级线程与内核级线程:一个栈到一套栈
    在这里插入图片描述

在这里插入图片描述

多线程模型

  • 一对一模型

    • 在这里插入图片描述

      • 每个用户级线程映射到一个内核级线程上

      • 创建线程开销大,切换频繁影响应用程序性能

  • 多对一模型

    • 在这里插入图片描述

      • 经多个用户级线程映射到一个内核级线程,线程管理在用户空间完成,用户级线程对操作系统不可见

      • 线程管理在用户控件,无需切换

      • 一个线程阻塞,全部线程阻塞

  • 多对多模型

    • 在这里插入图片描述
      • 多个线程映射到多个内核线程上

      • 结合上述两种,既可提高并发性,有降低开销

      • 用户级线程:代码逻辑载体

      • 内核级线程:运行机会载体

线程思维导图

在这里插入图片描述

调度器/调度程序(scheduler)

在这里插入图片描述
在这里插入图片描述

闲逛进程

在这里插入图片描述

处理机调度

调度

调度的层次
  • 作业调度(高级调度)

    • 每个作业只能调入一次,调出一次

      • 辅存<—>内存
        在这里插入图片描述
  • 内存调度(中级调度)

    • 将不能运行的进程调至外存,具备运行条件的进程调入内存,提高内存利用率和系统吞吐量

      • 内存<—>外存,就绪态<—>挂起态
        在这里插入图片描述
  • 进程调度(低级调度)

    • 按某策略从就绪队列选取一个进程分配处理机

      • 处理机<—>内存,最基本,高频
        在这里插入图片描述
三层调度的联系、对比

在这里插入图片描述

调度的时机

什么是临界区?
答:每个进程中访问临界资源的那段程序称为临界区(临界资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区,进入后不允许其他进程进入。

  • 不能切换的情况

    • 处理中断过程

    • 进程在操作系统内核程序临界区的时候

    • 其他需要完全屏蔽中断的原子操作过程

  • 可以切换的情况

    • 发生引起调度条件且当前进程无法继续进行(非剥夺)

    • 中断处理结束或者自陷处理结束后(剥夺)

    • 具体

      • 创建新进程
        在这里插入图片描述
        在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

进程调度方式
  • 非剥夺调度方式

    • 高优先级进程需要等待占用处理机的进程释放

    • 实现简单开销小,适合大多数批处理系统,不适用于分时系统和大多数实时系统

  • 剥夺调度方式

    • 暂停执行的进程,处理机分配给更高级进程

    • 提高系统吞吐量和响应效率
      在这里插入图片描述

进程的切换与过程

在这里插入图片描述

进程调度思维导图

在这里插入图片描述

调度的参考(调度算法评价指标)
  • CPU利用率:尽可能保持CPU处于忙碌状态=忙碌时间/总时间在这里插入图片描述

  • 吞吐量:完成的任务量=总完成任务数/总花费时间在这里插入图片描述

  • 周转时间:从任务进入到任务结束在这里插入图片描述
    在这里插入图片描述

  • 等待时间:作业等待处理机时间=周转时间-运行时间-I/O操作时间

    • 作业需计算在外存后备队列中的等待时间在这里插入图片描述
  • 响应时间:从操作发生到响应在这里插入图片描述

  • 响应时间小->切换次数多->系统内耗大->吞吐量小

  • 前台任务关注响应时间,后台任务关注周转时间

  • CPU约束型任务:CPU多、I/O少

  • I/O约束型任务:I/O多、CPU少

    • 优先级高
调度算法的评价指标思维导图

在这里插入图片描述

进程的挂起态与七状态模型

  • 在这里插入图片描述

    • 挂起态:暂时调到外存等待的进程状态为挂起状态

    • 挂起态和阻塞态都是暂时不能获得CPU服务,挂起态将进程映像调到外存,阻塞态仍在内存

处理机调度思维导图

在这里插入图片描述

经典调度算法

先来先服务算法 FCFS
  • 有利于CPU繁忙,不利于I/O繁忙型作业

    • 不会饥饿
      在这里插入图片描述

在这里插入图片描述

短作业优先算法 SJF
  • 非抢占式算法(若抢占式,则为最短剩余时间优先算法)

    • 可能饥饿
      在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对FCFS和SJF两种算法的思考…

在这里插入图片描述

高响应比调度算法 HRRN
  • 响应比=(等待时间+要求服务时间)/要求服务时间

    • 不会饥饿,非抢占式算法
      在这里插入图片描述

在这里插入图片描述

三种算法总结

在这里插入图片描述

时间片轮转算法 RR
  • 时间片用完进入就绪队列队尾

    • 不会饥饿,抢占式算法
      在这里插入图片描述

例1,0~5
在这里插入图片描述

例1,6~11

在这里插入图片描述
例1,12~16

在这里插入图片描述

例2,0~16

在这里插入图片描述
若按照先来先服务调度算法…

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

优先级调度算法
  • 原则

    • 系统进程>用户进程

    • 交互型进程>非交互型进程

    • I/O进程>计算型进程(CPU繁忙型)

    • 前台进程>后台进程

  • 可能饥饿

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

思考

在这里插入图片描述

多级反馈队列调度算法
  • 在这里插入图片描述

    • 设置多个就绪队列,每个队列赋予不同优先级

      • 第一级队列优先级最高,依次递减
    • 赋予每个队列的进程运行时间片大小各不相同

      • 优先级高,进程时间片小
    • 每个队列都采用FCFS算法

      • 第n级队列后,采用时间片轮转算法
    • 按队列优先级调度

      • 只有高级队列为空时,低等级队列才能调度

        • 若被抢占,则未运行完队列回到本队列队尾
    • 优势

      • 终端型作业用户:短作业优先

      • 短批处理作业用户:周转时间较短

      • 长批处理作业用户:经过前面几个队列部分执行,不会长时间不处理

    • 可能饥饿,抢占式算法
      在这里插入图片描述

在这里插入图片描述

三种算法总结

在这里插入图片描述

多级队列调度算法
  • 在这里插入图片描述

    • 设置多个就绪队列,将不同类型或性质的进程固定分配到不同就绪队列

    • 队列间可采用

      • 固定优先级:高优先级空时优先级低才能调用

      • 时间片划分:例如,列队分配时间50%、40%、10%

    • 各队列可不同调度策略:系统队列采用优先级调度、交互式队列采用RR、批处理队列采用FCFS

进程同步与互斥

基本概念

临界资源
  • 概念:一次只允许一个进程使用的资源

  • 访问过程

    • 进入区:检查进程是否可以进入临界区(“上锁”)

    • 临界区:可以访问临界资源的代码

    • 退出区:将正在访问临界区的标志清除(“解锁”)

    • 剩余区:代码中的其余部分

同步
  • 直接制约关系,为了完成某任务而建立的多个进程,需要互相通信同步

    • 原则

      • 空闲让进

        • 临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区
      • 忙则等待

        • 已有进程进入临界区后,其他试图进入临界区的进程必须等待
      • 有限等待

        • 对于请求访问临界区的进程,在有限时间内进入临界区
      • 让权等待

        • 进程不能进入临界区的时候,应当立即释放处理机
          在这里插入图片描述
互斥
  • 间接制约关系,当一个进程访问临界资源时,其他进程不能访问在这里插入图片描述

    在这里插入图片描述

同步、互斥思维导图

在这里插入图片描述

实现临界区互斥的基本方法

软件实现方法
  • 单标志法

    • 在这里插入图片描述

      • 仅交替进入,若A轮到不用,B也不能

      • 违背“空闲让进”

  • 双标志法先检查

    • 在这里插入图片描述

      • 1、2未经上锁,非一气呵成

      • 违背“忙则等待”

  • 双标志法后检查

    • 在这里插入图片描述

      • 同理未一气呵成,违背了“空闲让进”和“有限等待”,长期会产生饥饿
  • 皮特森算法

    • 在这里插入图片描述

      • 新增标志位,表谦让,最后一个谦让turn=0,则失去机会

      • 未遵循“让权等待”

进程互斥的软件实现方法思维导图

在这里插入图片描述

硬件实现方法
  • 中断屏蔽法

    • 对中断屏蔽,关中断防止其他进程进入临界区

    • 不适用于多处理机、仅适用于操作系统内核进程
      在这里插入图片描述

  • 硬件指令法(TS指令、TSL指令、Swap指令)

    • 硬件逻辑直接实现指令,不会被中断,从而实现进程互斥

在这里插入图片描述
在这里插入图片描述

  • 以上都未遵循“让权等待”
    在这里插入图片描述

进程互斥:锁

在这里插入图片描述

在这里插入图片描述

信号量

  • 概念引入

    • 由于进程异步问题,走走停停

      • 需要发信号来约束

        • 信号只能反映有无,引入信号量表达更多消息
  • 三种操作:P操作、V操作、创建
    在这里插入图片描述

  • 整形信号量

    • 定义一个用于表示资源数目的整型量

    • 没有遵循让权等待,导致进程处于“忙等”状态
      在这里插入图片描述

  • 记录形信号量

    • 记录型信号量不存在“忙等”现象,除了需要一个用于代表资源数目的整型变量value外,增加一个进程链表,用于链接所有等待该资源的进程
      在这里插入图片描述
      在这里插入图片描述
  • 解决一气呵成问题,无法“让权等待”

信号量机制思维导图

在这里插入图片描述

管程(类似于类)

在这里插入图片描述

  • 概念

    • 一组数据以及定义在这组数据上的对这组数据的操作组成的软件模块,这组操作能初始化并改变管程中数据和同步进程
  • 组成

    • 局部于管程的共享结构数据说明

    • 对该数据结构进行操作的一组过程

    • 对局部于管程的共享数据设置初始值的语句

  • 基本特征

    • 局部于管程的数据只能被局部于管程内的过程所访问

    • 一个进程只有通过调用管程内的过程才能进入管程访问共享数据

    • 每次仅允许一个进程在管程内执行某一个内部过程
      在这里插入图片描述

拓展

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

管程思维导图

在这里插入图片描述

经典同步问题

  • 核心

    • 实现互斥

      • 初值为1,前P后V
        在这里插入图片描述
    • 实现同步

      • 初值为0,前V后P
        在这里插入图片描述
    • 实现前驱关系

      • 在这里插入图片描述

信号量机制思维导图

在这里插入图片描述

  • 以下具体问题,提一下王道的重点思路,可以考前听王道

- 生产者-消费者问题

- 多生产者-多消费者问题

  • 若盘子数为1,可省去mutex,本身访问互斥

- 吸烟者问题

- 读者-写者问题

  • 增加P(w)、V(w)使写优先,防止源源不断读者,饥饿问题

  • 增加互斥信号量使count–和if(count==0)一气呵成

- 哲学家进餐

  • 思路一:最多允许四位同时吃饭

  • 思路二:奇数号哲学家先拿左筷子,偶数号相反

  • 思路三:仅当哲学家左右能同时拿起筷子时进食(拿筷子的动作加互相信号,一气呵成)

死锁

死锁的概念

  • 两个或两个以上的进程在执行过程中,由于竞争资源而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去
    在这里插入图片描述
死锁产生的原因
  • 系统资源的竞争(不可剥夺资源)

  • 进程推进顺序非法

  • 产生的必要条件(同时满足)

    • 互斥条件:进程对分配的资源进行排他性控制

    • 不可剥夺条件:进程获得资源在未使用完之前,不能被其他进程强行夺走

    • 请求并保持条件:进程已经保持了至少一个资源,提出新的资源请求被阻塞,但是自己已经获得的资源保持不放

    • 循环等待条件:你等我释放,我等你释放
      在这里插入图片描述
      在这里插入图片描述

死锁的概念思维导图

在这里插入图片描述

死锁的处理策略

在这里插入图片描述

死锁预防
  • 破坏互斥条件

    • 某些资源只能被互斥访问,某些情况下必须保护互斥性在这里插入图片描述
  • 破坏不剥夺条件

    • 释放已经占有的资源(主动,操作系统协助剥夺)在这里插入图片描述
  • 破坏请求并保持条件

    • 一次性申请完所需要的全部资源(静态分配法)在这里插入图片描述
  • 破坏循环等待条件

    • 采用顺序资源法,对进程进行顺序推进(对进程编号)在这里插入图片描述
预防死锁思维导图

在这里插入图片描述

死锁避免

在这里插入图片描述

  • 系统安全状态

    • 指系统能按某种推进顺序为每个进程分配其所需的资源,直至满足每个进程对资源的最大需求,每个进程都可顺利完成
    • 在这里插入图片描述
  • 银行家算法

    • 在这里插入图片描述

      • 概念(三个矩阵图片中从左到右)

        • 可利用资源向量Available:m个元素的数组,每个元素代表一类可用资源数目

        • 最大需求矩阵Max:n个进程中每个进程对m类资源最大需求

        • 分配矩阵Allocation:系统中每类资源已经分配给每个进程的数量

        • 需求矩阵Need:表示接下来每个进程最多还要多少资源

        • 矩阵关系:Need=Max-Allocation

      • 执行

        • 判断剩余资源是否能满足需求矩阵中进程,若满足回收已分配资源,继续判断,直到所有资源都被分配完,若无一满足则回溯

在这里插入图片描述
在这里插入图片描述

  • 不安全的例子
    在这里插入图片描述
  • 代码实现
    在这里插入图片描述
银行家算法总结

在这里插入图片描述

死锁的检测和解除
  • 资源分配图

    • 在这里插入图片描述
      • 绿色箭头:资源分配边

      • 蓝色箭头:申请资源边

      • 圈圈为进程、框为一类资源(框内圆点为拥有的资源)
        在这里插入图片描述
        死锁实例
        在这里插入图片描述
        在这里插入图片描述

  • 死锁定理

    • 在资源分配图中找到分配满足的进程,然后消去请求边与分配边

    • 若所有边都可以被消去,则不存在死锁,反之存在死锁
      在这里插入图片描述

  • 死锁解除

    • 资源剥夺法

      • 挂起某些死锁进程,抢占资源,将这些资源分配给其他死锁进程,但需要防止挂起时间过长
    • 撤销进程法

      • 强制撤销部分甚至全部死锁进程,剥夺他们的资源

        • 选择原则:优先级、已执行时间、还要多久完成、已用资源数、交互式/批处理式
    • 进程回退法

      • 让一个或者多个进程回退到足以回避死锁的地步,进程回退时自愿释放资源而非被剥夺(要求系统保持进程历史信息,设置还原点)

在这里插入图片描述

死锁的检测和解除思维导图

在这里插入图片描述

死锁、饥饿、死循环的区别

  • 死锁:各进程相互等待对方手里的资源,导致各进程都阻塞,无法向前推进的现象(操作系统解决)

  • 饥饿:由于长期得不到想要的资源,某进程无法向前推进的现象(操作系统解决)

  • 死循环:某进程执行过程中一直跳不出某个循环的现象(程序员解决)

在这里插入图片描述

408 - 2023

26. 导致CPU从内核态转为用户态的操作

问题: 下列操作完成时,导致CPU从内核态转为用户态的是( )。

A. 阻塞过程
B. 执行CPU调度
C. 唤醒进程
D. 执行系统调用

参考答案:

正确答案是选项 D:执行系统调用。

解析:

操作系统通过执行软中断指令陷入到内核态执行系统调用,也就是用户进程请求内核提供服务。在这个过程中,CPU从用户态切换到内核态。系统调用执行完成后,会恢复被中断的或设置新进程的CPU现场,然后返回被中断进程或新进程,这时CPU会从内核态切换回用户态。

选项 A、B、C 中的操作虽然都是在内核态进行的,但是它们并不导致CPU从内核态切换到用户态。阻塞过程、执行CPU调度和唤醒进程都是在操作系统内部进行的,并没有涉及用户程序的执行。只有执行系统调用时,用户进程才会调用内核提供的功能,此时CPU会从用户态切换到内核态,执行相应的内核代码,处理用户进程的请求,并在返回时将CPU从内核态切换回用户态。

因此,只有执行系统调用时,CPU才会从内核态转为用户态。

正确答案是选项 D:执行系统调用。

27. 导致线程由执行态变为就绪态的事件或操作

问题: 下列出当前线程引起的事件或执行的操作中,可能导致该线程由执行态变为就绪态的是( )。

A. 键盘输入
B. 缺页异常
C. 主动出让CPU
D. 执行信号量的wait()操作

参考答案:

正确答案是选项 C:主动出让CPU。

解析:

  • A. 键盘输入:当等待键盘输入的操作进行时,当前线程处于阻塞态。键盘输入完成后,会调用相应的中断服务程序来处理输入,而不是唤醒当前线程。因此,键盘输入不会导致线程由执行态变为就绪态。选项 A 错误。

  • B. 缺页异常:当线程检测到缺页异常时,会调用缺页异常处理程序从外存调入缺失的页面,但线程的状态从执行态转为阻塞态,而非就绪态。因此,缺页异常不会导致线程由执行态变为就绪态。选项 B 错误。

  • C. 主动出让CPU:当线程的时间片用完后,可以选择主动放弃CPU,以便其他线程能够执行。此时,线程会进入就绪队列,等待下次调度执行,因此导致线程由执行态变为就绪态。选项 C 正确。

  • D. 执行信号量的wait()操作:线程执行wait()操作后,若成功获取资源,则线程状态不会改变,仍然保持在执行态。若未能获取资源,则线程会进入阻塞态,而不是就绪态。因此,执行信号量的wait()操作不会导致线程由执行态变为就绪态。选项 D 错误。

综上所述,只有主动出让CPU的操作可以导致线程由执行态变为就绪态。

正确答案是选项 C:主动出让CPU。

29. 进程调度和平均周转时间

问题: 进程Pl,P2和P3进入就绪队列的时刻,优先值(越大优先权越高)以及CPU的执行时间如下表所示。

系统采用基于优先权的抢占式CPU调度算法,从Oms时刻开始进行调度,则P1,P2,P3的平均周转时间为()

进程名进入就绪队列的时刻优先数CPU的执行时间
P1Oms160ms
P220ms1042ms
P330ms10015ms

A. 60ms
B. 61ms
C. 70ms
D. 71ms

参考答案:

正确答案是选项 B:61ms。

解析:

根据给定的进程信息和采用基于优先权的抢占式CPU调度算法,我们可以得出进程的执行顺序如下:

  1. 在0ms时刻,P1进入就绪队列,由于它的优先数最低,因此被选择执行。
  2. P1执行60ms后,在60ms时刻完成。
  3. 在20ms时刻,P2进入就绪队列,由于它的优先数较高,比P1的优先数大,因此抢占CPU并开始执行。
  4. P2执行42ms后,在62ms时刻完成。
  5. 在30ms时刻,P3进入就绪队列,由于它的优先数最高,比P1和P2的优先数都大,因此抢占CPU并开始执行。
  6. P3执行15ms后,在77ms时刻完成。

根据上述计算可得到每个进程的周转时间:

  • P1的周转时间 = 完成时间 - 到达时间 = 60ms - 0ms = 60ms
  • P2的周转时间 = 完成时间 - 到达时间 = 62ms - 20ms = 42ms
  • P3的周转时间 = 完成时间 - 到达时间 = 77ms - 30ms = 47ms

因此,平均周转时间 = (60ms + 42ms + 47ms) / 3 = 149ms / 3 ≈ 49.67ms ≈ 61ms。

因此,选项 B:61ms 是正确答案。

正确答案是选项 B:61ms。

408-2022

25. 进程调度次数

问题: 进程P0、P1、P2和P3进入就绪队列的时刻、优先级(值越小优先权越高)及CPU执行时间如下表所示。

进程进入就绪队列的时刻优先级CPU执行时间
P00ms15100ms
P110ms2060ms
P210ms1020ms
P315ms610ms

若系统采用基于优先权的抢占式进程调度算法,则从0ms时刻开始调度,到4个进程都运行结束为止,发生进程调度的总次数为( )。

A. 4
B. 5
C. 6
D. 7

参考答案:

正确答案是选项 C:6。

解析:

根据给定的进程信息和使用的调度算法,我们可以推导出进程的调度情况。以下是每次发生进程调度的时刻:

  • 0ms:进程P0获得CPU,这是第一次调度。
  • 10ms:进程P2进入就绪队列,抢占了CPU,这是第二次调度。
  • 15ms:进程P3进入就绪队列,抢占了CPU,这是第三次调度。
  • 25ms:进程P0执行完毕,调度进程P2获得CPU,这是第四次调度。
  • 40ms:进程P2执行完毕,调度进程P0获得CPU,这是第五次调度。
  • 130ms:进程P0执行完毕,调度进程P1获得CPU,这是第六次调度。

总共发生进程调度的次数为6次。

因此,正确答案是选项 C:6。

26. 安全序列的个数

问题: 系统中有三个进程P0、P1、P2及三类资源A、B、C。若某时刻系统分配资源的情况如下表所示,则此时系统中存在的安全序列的个数为( )。

进程已分配资源数尚需资源数可用资源数
ABC
P0201
P1020
P2101

A. 1
B. 2
C. 3
D. 4

参考答案:

正确答案是选项 B:2。

解析:

根据给定的分配和需求资源情况,我们需要找到能够形成安全序列的调度顺序。以下是一种可能的安全序列:

  • 安全序列 1: P0 → P2 → P1

首先,进程P0已经获得了所有所需的资源,因此可以执行,并在执行完毕后释放所占用的资源。此时可用资源数变为<3, 3, 3>。根据当前可用资源数,我们可以选择调度进程P2或P1。无论我们选择调度哪个进程,它们都能够满足它们的需求并执行完毕后释放资源。因此,我们可以形成两个不同的安全序列。

因此,存在两个安全序列。

正确答案是选项 B:2。

28. 进程状态的转换

问题: 下列事件或操作中,可能导致进程P由执行态变为阻塞态的是( )。

Ⅰ. 进程P读文件

Ⅱ. 进程P的时间片用完

Ⅲ. 进程P申请外设

Ⅳ. 进程P执行信号量的wait()操作

A. 仅Ⅰ、Ⅳ
B. 仅Ⅱ、Ⅲ
C. 仅Ⅲ、Ⅳ
D. 仅Ⅰ、Ⅲ、Ⅳ

参考答案:

正确答案是选项 A:仅Ⅰ、Ⅳ。

解析:

在给定的事件和操作中,以下是可能导致进程P由执行态变为阻塞态的情况:

Ⅰ. 进程P读文件:当进程P读取文件时,它需要等待磁盘IO完成,这将导致进程从执行态变为阻塞态。

Ⅱ. 进程P的时间片用完:当进程P的时间片用完时,它会从执行态变为就绪态,并等待下次被调度。它不会直接从执行态变为阻塞态。

Ⅲ. 进程P申请外设:进程P申请外设,如果该外设是独占设备且正在被其他进程使用,那么进程P将从执行态变为阻塞态,等待系统分配外设。

Ⅳ. 进程P执行信号量的wait()操作:如果进程P执行信号量的wait()操作,并且该信号量的值小于等于0,那么进程将进入阻塞态,等待其他进程使用signal()操作唤醒。

综上所述,正确答案是选项 A:仅Ⅰ、Ⅳ。

正确答案是选项 A:仅Ⅰ、Ⅳ。

408-2021

24. 创建新进程时必须完成的操作

问题: 下列操作中,操作系统在创建新进程时,必须完成的是( )。

Ⅰ. 申请空白的进程控制块
Ⅱ. 初始化进程控制块
Ⅲ. 设置进程状态为执行态

A. 仅Ⅰ
B. 仅Ⅰ、Ⅱ
C. 仅Ⅰ、Ⅲ
D. 仅Ⅱ、Ⅲ

参考答案:

正确答案是选项 B:仅Ⅰ、Ⅱ。

解析:

在操作系统创建新进程时,必须完成以下两个操作:

Ⅰ. 申请空白的进程控制块:每个进程都需要一个进程控制块 (Process Control Block, PCB) 来描述和管理它的信息。PCB包含了进程的各种属性和状态,如进程标识符、优先级、程序计数器、寄存器值等。因此,在创建新进程之前,操作系统必须为其分配一个空白的进程控制块。所以选项 Ⅰ 正确。

Ⅱ. 初始化进程控制块:创建进程后,操作系统需要初始化进程控制块,将一些必要的信息填入其中。这包括设置进程的初始状态、分配资源、初始化处理机状态信息、设置进程优先级等。通过初始化进程控制块,操作系统确保了进程的正确运行和管理。因此,选项 Ⅱ 正确。

而设置进程状态为执行态是在进程调度过程中进行的,并不是创建新进程时必须完成的操作。所以,选项 Ⅲ 错误。

综上所述,操作系统在创建新进程时必须完成的操作是申请空白的进程控制块 (Ⅰ) 和初始化进程控制块 (Ⅱ)。

正确答案是选项 B:仅Ⅰ、Ⅱ。

25. 分时系统实现时间片轮转调度所需的数据结构或程序

问题: 下列内核的数据结构或程序中,分时系统实现时间片轮转调度需要使用的是( )。

Ⅰ. 进程控制块
Ⅱ. 时钟中断处理程序
Ⅲ. 进程就绪队列
Ⅳ. 进程阻塞队列

A. 仅Ⅱ、Ⅲ
B. 仅Ⅰ、Ⅳ
C. 仅Ⅰ、Ⅱ、Ⅲ
D. 仅Ⅰ、Ⅱ、Ⅳ

参考答案:

正确答案是选项 C:仅Ⅰ、Ⅱ、Ⅲ。

解析:

在分时系统中,时间片轮转调度算法是一种常用的调度算法。为了实现时间片轮转调度,操作系统需要使用以下数据结构或程序:

Ⅰ. 进程控制块 (Process Control Block, PCB):进程控制块用于描述和管理每个进程的信息。PCB包含了进程的各种属性和状态,如进程标识符、程序计数器、寄存器值等。在时间片轮转调度中,需要通过修改进程控制块中的一些信息来实现调度算法。因此,选项 Ⅰ 正确。

Ⅱ. 时钟中断处理程序:时钟中断处理程序是一种特殊的中断处理程序,负责在每个时钟周期结束时执行一些操作。它通常会检查当前进程的时间片是否用完,如果是,则触发进程调度。在时间片轮转调度中,时钟中断处理程序会从就绪队列中选择一个进程,并为其分配时间片。因此,选项 Ⅱ 正确。

Ⅲ. 进程就绪队列:进程就绪队列用于存储所有处于就绪态的进程。在时间片轮转调度中,调度程序会从就绪队列中选择下一个要执行的进程,并为其分配时间片。因此,选项 Ⅲ 正确。

而进程阻塞队列并不直接参与时间片轮转调度过程。进程阻塞队列用于存储处于阻塞态的进程,在满足某些条件后才能被唤醒并转移到就绪队列中。因此,选项 Ⅳ 错误。

综上所述,分时系统实现时间片轮转调度所需要使用的数据结构或程序是进程控制块 (Ⅰ)、时钟中断处理程序 (Ⅱ) 和进程就绪队列 (Ⅲ)。

正确答案是选项 C:仅Ⅰ、Ⅱ、Ⅲ。

27. 引起进程调度程序执行的事件

问题: 下列事件中,可能引起进程调度程序执行的是( )。

Ⅰ. 中断处理结束
Ⅱ. 进程阻塞
Ⅲ. 进程执行结束
Ⅳ. 进程的时间片用完

A. 仅Ⅰ、Ⅲ
B. 仅Ⅱ、Ⅳ
C. 仅Ⅲ、Ⅳ
D. Ⅰ、Ⅱ、Ⅲ和Ⅳ

参考答案:

正确答案是选项 D:Ⅰ、Ⅱ、Ⅲ和Ⅳ。

解析:

以下是对每个事件进行解析:

Ⅰ. 中断处理结束:当系统发生中断时,会运行相应的中断处理程序。在中断处理程序执行完毕之后,需要根据具体情况来确定下一步的操作。如果中断处理程序触发了某些条件,例如当前进程的时间片用完,就会发生进程调度。因此,选项 Ⅰ 可能引起进程调度程序的执行。

Ⅱ. 进程阻塞:当一个进程发起阻塞请求时,它将被移出CPU,并放入阻塞队列等待满足其阻塞条件。此时,进程调度程序需要从就绪队列中选择另一个进程执行,以充分利用CPU资源。因此,选项 Ⅱ 可能引起进程调度程序的执行。

Ⅲ. 进程执行结束:当一个进程执行完毕时,它将释放CPU,并且进程调度程序需要选择下一个进程运行。因此,选项 Ⅲ 可能引起进程调度程序的执行。

Ⅳ. 进程的时间片用完:在一些调度算法中,例如时间片轮转调度算法,每个进程被分配一个时间片来使用CPU。当一个进程的时间片用完时,它将让出CPU,并且进程调度程序需要从就绪队列中选择下一个进程运行。因此,选项 Ⅳ 可能引起进程调度程序的执行。

综上所述,引起进程调度程序执行的事件包括中断处理结束(Ⅰ)、进程阻塞(Ⅱ)、进程执行结束(Ⅲ)和进程的时间片用完(Ⅳ)。

正确答案是选项 D:Ⅰ、Ⅱ、Ⅲ和Ⅳ。

31. 避免系统发生死锁所需的临界资源总数

问题: 若系统中有n(n≥2)个进程,每个进程均需要使用某类临界资源2个,则系统不会发生死锁所需的该类资源总数至少是( )。

A. 2
B. n
C. n+1
D. 2n

参考答案:

正确答案是选项 C:n+1。

解析:

死锁是指在多进程环境下,由于进程之间的互斥、占有和等待资源等特性,导致它们无法继续执行的状态。而避免死锁的关键在于合理地分配和管理资源。

根据题目给出的条件:

  • 系统中有n个进程。
  • 每个进程都需要使用某类临界资源2个。

为了避免死锁发生,我们需要确保所有进程都能够获得足够的资源以继续执行,即不存在进程无法满足资源需求的情况。

考虑极端情况:

当临界资源数为n时,每个进程仅拥有1个临界资源并等待另一个资源,这种情况下会发生死锁。

当临界资源数为n+1时,至少有一个进程可以获得2个临界资源,顺利运行完后释放自己的临界资源,使得其他进程也能顺利运行,不会产生死锁。

另一种解释方式是使用死锁公式 m > n * (r-1),其中 m 是系统中临界资源的总数,n 是并发进程的个数,r 是每个进程所需临界资源的个数。如果这个不等式成立,那么系统不会发生死锁。将本题的数据代入,得到 m > n * (2-1),即只要系统中临界资源的总数至少是 n+1,就可以避免死锁。

因此,为了避免死锁发生,该类临界资源总数至少为 n+1。

正确答案是选项 C:n+1。

未完待续,逐张试卷整理中,会一直更新到2009

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

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

相关文章

ARM 基础学习记录 / 异常与GIC介绍

GIC概念 念课本&#xff08;以下内容都是针对"通用中断控制器&#xff08;GIC&#xff09;"而言&#xff0c;直接摘录的&#xff0c;有的地方可能不符人类的理解方式&#xff09;&#xff1a; 通用中断控制器&#xff08;GIC&#xff09;架构提供了严格的规范&…

MySQL时间类型注意事项

MySQL常见的时间类型有YEAR、DATE、TIME、DATETIME、TIMESTAMP&#xff0c;绝大多数业务都是精确到秒的&#xff0c;所以通常用后两种。并且MySQL5.6以后后两种支持精度到毫秒&#xff08;最多小数点后6位&#xff09; DATETIME占8字节&#xff0c;不论要不要毫秒 TIMESTAMP占4…

物业管理服务预约小程序的效果如何

物业所涵盖的场景比较多&#xff0c;如小区住宅、办公楼、医院、度假区等&#xff0c;而所涵盖的业务也非常广&#xff0c;而在实际管理中&#xff0c;无论对外还是对内也存在一定难题&#xff1a; 1、品牌展示难、内部管理难 物业需求度比较广&#xff0c;设置跨区域也可以&…

Python之函数-作用域和嵌套函数

Python之函数-作用域和嵌套函数 作用域 一个标识符的可见范围&#xff0c;这就是标识符的作用域。一般常说的是变量的作用域每一个函数都会开辟一个作用域 作用域分类 全局作用域 在整个程序运行环境中都可见全局作用域中的变量称为全局变量global 局部作用域 在函数、类等…

【Python 千题 —— 基础篇】成绩评级

题目描述 题目描述 期末考试结束&#xff0c;请根据同学的分数为该同学评级。 A&#xff1a;90 ~ 100B&#xff1a;80 ~ 89C&#xff1a;70 ~ 79D&#xff1a;60 ~ 69E&#xff1a;0 ~ 60 输入描述 输入同学的分数。 输出描述 输出该同学的等级。 示例 示例 ① 输入&…

张小泉的“老字号”快守不住了:限期整改,业绩和产品各有危机

撰稿|行星 来源|贝多财经 11月8日&#xff0c;商务部等5部门发布了中华老字号的复核结果。结果显示&#xff0c;全国有981家中华老字号企业通过了复核&#xff0c;73家中华老字号企业附条件通过复核&#xff0c;另有55家企业未能通过复核。 贝多财经发现&#xff0c;张小泉股…

Pycharm常用快捷键和替换正则表达式

原生快捷键的使用&#xff1a; 1.CtrlF&#xff1a;查找 2.CtrlZ&#xff1a;返回上一步 3.Alt 鼠标左键选择&#xff1a;多行同时编辑&#xff08;上、下、左、右键能够移动光标&#xff09; 按住Ctrl,左键点击&#xff0c;定位光标 编辑过程 URL常用的替换正则表达式&am…

Echarts多条折线图 y轴与实时值提示框数值不一致解决方法:

Echarts多条折线图 y轴与实时值提示框数值不一致解决方法&#xff1a; 删除stack属性即可 stack看官网就是数据堆叠 发现这个bug&#xff0c;特此记录

【数据结构】树与二叉树(十):二叉树的先序遍历(非递归算法NPO)

文章目录 5.2.1 二叉树二叉树性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点&#xff0c;其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…

【Linux(0)】为什么要学习Linux,为什么互联网公司在招聘时,会提出要有Linux经验,及其使用;一些Linux常见指令

前言 &#x1f493;作者简介&#xff1a; 加油&#xff0c;旭杏&#xff0c;目前大二&#xff0c;正在学习C&#xff0c;数据结构等&#x1f440; &#x1f493;作者主页&#xff1a;加油&#xff0c;旭杏的主页&#x1f440; ⏩本文收录在&#xff1a;再识C进阶的专栏&#x1…

Yum配置、相关命令和常见问题

搭建光盘源 将系统盘读取出来&#xff0c;找到系统盘下存放软件包的目录 2.配置yun仓库 输入命令进入仓库编辑 #必须以.repo结尾 :wq 回车保存退出 3.命令行输入yum repolist 查看yum仓库 配置硬盘源 1.将硬盘源拷贝到目录&#xff0c;或者挂载到目录 2.指定repo文件baseu…

Vue 3 打印解决方案:Vue-Plugin-HiPrint

文章目录 1. Vue-Plugin-HiPrint 简介2. 安装和使用2.1 安装2.2 引入并注册插件2.3 在组件中使用 3. 配置和高级用法4. 示例应用5. 总结 &#x1f389;欢迎来到Java学习路线专栏~Vue 3 打印解决方案&#xff1a;Vue-Plugin-HiPrint ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f37…