如需转载,请根据 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 许可,附上本文作者及链接。
本文作者: Alice
作者昵称: 沉。
本文链接: http://example.com/2020/11/04/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%EF%BC%88%E4%B8%80%EF%BC%89/
一、操作系统的基本概念
1.1、操作系统的定义,功能和目标
操作系统介于应用程序和硬件之间的一层系统软件
操作系统的定义:操作系统是指控制和冠以整个计算机系统的硬件和软件资源,并合理的组织调度计算机的工作和资源的分配,是提供给用户和其他软件方便的接口和环境,它是计算机系统汇总最基本的系统软件。
进程是一个程序的执行过程,执行前需要将该程序放到内存中,才能被CPU处理
1.1.1、操作系统作为系统资源的管理者,需要提供什么功能?
- 处理机管理
- 存储器管理
- 文件管理
- 设备管理
- 目标:安全高效
1.1.2、操作系统作为用户与计算机硬件之间的接口,需要为上层的用户、应用程序提供简单易用的服务,需要实现什么功能?
- 命令接口:允许用户直接使用
- 联机命令接口=交互式命令接口:用户说一句,系统左一句
- 脱机命令接口=批处理命令接口:用户说一堆,系统做一堆
- 程序接口:允许用户通过程序简介使用:由一组系统调用组成(程序接口=系统调用)
- GUI:现在操作系统中最流行的图形用户接口,用户可以在使用形象的图形界面进行操作,而不再需要记忆复杂的命令、参数。
- 目标:方便用户使用
- 系统调用=系统调用命令=广义指令
1.1.3、操作系统作为最接近硬件的层次,需要在纯硬件的基础上实现什么样的功能?
- 需要提供功能和目标:实现对硬件机器的拓展
- 没有任何软件支持的计算机称为裸机。在裸机上安装的操作系统,可以提供资源管理功能和方便用户的服务功能,将裸机改造成功能更强、使用更方便的机器
- 通常把覆盖了软件的机器称为扩充机器,又称之为虚拟机
1.2、操作系统的特征
并发:指两个或多个事件在同一时间间隔内发生。这些事件宏观上是同时发生的,但微观上时交替发生的。
并行:指两个或多个事件在同一时刻同时发生。
操作系统的并发性指计算机操作系统中同时存在着多个运行着的程序。
操作系统和程序并发是一起诞生的
共享:即资源共享,是指系统汇总的资源可供内存中多个并发执行的进程共同使用
- 互斥共享方式
- 同时共享方式
并发和共享的关系:
- 并发性指计算机系统中同时存在着多个运行着的程序
- 共享性是指系统中的资源可供内存中多个并发执行的进程共同使用
- 如果失去并发性,系统中只有一个程序正在运行,则共享性失去存在的意义
- 如果失去共享性,则QQ和微信不能同时访问硬盘资源,就无法实现同时发送文件,也就无法并发
虚拟:虚拟是指把一个物理上的实体变为若干个逻辑上的对应物。物理实体(前者)是实际存在的,而逻辑上对应物(后者)是用户感受到的
虚拟技术:
- 空分复用技术(如虚拟存储器技术)
- 时分复用技术(如虚拟处理器)
异步:异步式指在多道程序环境下,允许多个程序并发执行,但由于资源有限,今后才能的执行不是一贯到底的,而是走走停停的,以不可预知的速度向前推进,这就是进程的异步性。
1.3、操作系统的发展和分类
1.3.1、手工操作阶段
主要缺点:用户独占全机、人机速度矛盾导致资源利用率极低
批处理阶段——单道批处理系统:引入脱机输入/输出技术(用磁带完成),并监督程序(操作系统的雏形)负责控制作业的输入,输入
- 缓解了一定程度的人机速度矛盾,资源利用率有所提升。
- 主要缺点:内存中仅能有一道程序运行,只有该程序运行结束之后才能调入下一道程序,CPU有大量的事件是在空闲等待I/O完成。资源利用率依然很低。
1.3.2、批处理系统
批处理系统——多道批处理系统:每次网内存中输入多道程序,操作系统正式诞生,并引入了中断技术,由操作系统负责管理这些程序的运行。各个程序并发执行。
主要优点:多道程序并发执行,共享计算机资源。资源利用率大幅提升,CPU和其他资源保持“忙碌”状态,系统吞吐量增加。
主要缺点:用户响应时间长,没有人机交互功能(用户提交自己的迆之后就只能等待计算机处理完成,中间不能控制自己的作业执行)
1.3.3、分时和实时操作系统
分时操作系统:计算机以时间片为单位轮流为各个用户/作业服务,各个用户可通过终端与计算机进行交互。
主要优点:用户请求可以被即时响应,解决了人机交互的问题,允许多个用户同时使用一台计算机,并且用户对计算机的操作相互独立,感受不到别人的存在。
主要缺点:不能优先处理一些紧急任务。操作系统对各个用户/作业都是完全公平的,循环地为每个用户/作业服务一个时间片,不区分任务的紧急性
实时操作系统:
- 主要优点::能够优先响应一些紧急任务,某些紧急任务不需时间片排队
- 在实时操作系统的控制下,计算机系统接收到外部信号后即时进行处理,并且要在严格的时限内处理完事件。实时操作系统的主要特点是及时性和可靠性
- 硬实时系统:必须在绝对严格的规定时间内完成处理
- 软实时系统:能接受偶尔违反时间规定
1.3.4、其他的几种操作系统:
1.4、操作系统的运行机制和体系结构
1.4.1、运行机制
指令:就是处理器(CPU)能识别。执行的最基本命令
- 特权指令:如内存清零指令
- 非特权指令:如普通的运算指令
两种处理器状态:用程序状态字寄存器(PSW)中的某标志位来表示当前处理器处于什么状态,如0为用户态,1位核心态
- 用户态(目态)此时CPU只能执行非特权指令
- 核心态(管态)特权指令、非特权指令都可以执行
两种程序:
- 内核程序:操作系统的内核程序式系统的管理者,既可以执行特权指令,也可以执行非特权指令,运行在核心态
- 应用程序:为了保证系统能安全运行,普通应用程序只能执行非特权指令,运行在用户态
1.4.3、操作系统的内核
内核是计算机上配置的底层软件,是操作系统最基本,最核心的部分
实现操作系统内核功能的那些程序就是内核程序。
操作系统的体系结构:
- 大内核
- 将操作系统中的主要功能模块都作为系统内核,运行在核心态
- 优点:高性能
- 缺点:内核代码庞大,结构混乱,难以维护
- 微内核
- 只把最基本的功能保留在内核
- 优点:内核功能少,结构清晰,方便维护
- 缺点:需要频繁的在核心态和用户态之间切换,性能低
1.5、中断和异常
1.5.1、中断机制
引入中断机制,实现了多道程序并发执行。
本质:发生中断就意味着需要操作系统接入,开展管理工作。
- 用户态下:CPU收到计时部件发出的中断信号,切换为核心态对中断进行处理
- 核心态下:操作系统内核负责对中断信号进程进行处理
中断的概念和作用:
- 当中断发生时,CPU立即进入核心态
- 当中断发生后,当前运行的进程暂停运行,并由操作系统内核对中断进行处理
- 对于不同的中断信号,会进行不同的处理
- 发生了中断,就意味着需要操作系统接入,开展管理工作。由于操作系统的管理工作(比如进程切换、分配I/O设备等)需要使用特权指令、因此CPU要从用户态转为核心态,中断可以使CPU从用户态切换为核心态,使操作系统获得计算机的控制权,有了中断,才能实现多道程序并发执行。
- 用户态——>核心态 是通过中断实现的,并且中断是唯一途径
- 核心态——>用户态 切换是通过一个特权指令实现的。
1.5.2、中断的分类
中断分为内中断和外中断两大类:
另一种分类方式:
外中断的处理过程:
1.6、系统调用
系统调用:是操作系统提供给应用程序(程序员/编程人员)使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序可以发出系统调用请求来获得操作系统的服务。
应用程序通过系统调用请求操作系统的服务,系统中的各种跪下哪个资源都由操作系统统一掌管,因此在用户程序中,凡是与资源有关的操作(如存储分配、I/O操作、文件管理等),都必须通过系统调用的方式向操作系统提出服务请求,有操作系统代为完成。这样可以保证系统的稳定性和安全性,防止用户进行非法操作。
系统调用相关处理设置道对系统资源的管理,对进程的控制,这些工鞥需要执行一些特权指令才能完成,因此系统调用的相关处理需要在核心态下完成。
系统调用与库函数的区别:
系统调用背后的过程:
传递系统调用参数——执行陷入指令(用户态)——执行系统调用相应服务程序(核心态)——返回用户程序
- 注意:陷入指令是在用户态执行的,执行陷入指令之后立即引发一个内中断,从而CPU进入核心态
- 陷入指令是唯一一个只能在用户态执行,而不可在核心态执行的指令
- 发出系统调用请求是在用户态,而对系统调用的相应处理是在核心态下进行。
小结:
二、进程
2.1、进程的基本概念
程序:就是一个指令序列,早期的计算机(只支持单道程序)。
为了方便操作系统管理,完成各程序并发执行,引入了进程、进程实体的概念。
系统为每个运行的程序配置一个数据结构,称为进程控制块(PCB),用来描述进程的各种信息(如程序代码存放的位置)
PCB、程序段、数据段三部分构成了进程实体(进程映像)
进程的定义:程序段、数据段、PCB三部分组成了进程实体(进程映像)。一般情况下,我们吧进程实体就简称为进程,例如,所谓创建进程实质上是创建进程实体中的PCB:而撤销进程,实质上是撤销进程实体汇总的PCB。
注意:PCB是进程存在的唯一标志
从不同角度,进程可以有不同的定义,比较传统典型的定义有:
- 进程是程序的一次执行过程
- 进程是一个程序及其数据在处理机是哪个顺序执行时锁发生的活动。
- 进程是具有独立功能的程序在数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。
引入进程实体的概念后,可以把进程定义为:
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。
- 注意:严格来说,进程实体和进程并不一样,进程实体是静态的,进程则是动态的。
2.1.2、进程的组成
进程(进程实体)由程序段、数据段、PCB三部分组成
PCB中的信息:
- 进程描述信息
- 进程标识符PID
- 用户标识符UID
- 进程控制和管理进程
- 进程当前状态
- 进程优先级
- 资源分配清单
- 程序段指针、数据段指针、键盘、鼠标
- 处理机相关信息:各种寄存器值
2.1.3、进程的组织
在一个系统中,通常有数十,数百乃至数千个PCB。为了能对他们加以有效的管理,应该用适当的方式吧这些PCB组织起来。
注:进程的组成讨论的是一个进程内部由哪些部分构成的问题,而进程的组织讨论的是多个进程之间的组织方式问题。
进程的组织方式:
- 链接方式:
- 按照进程状态将PCB分为多个队列
- 操作系统持有指向各个队列的指针
- 索引方式:
- 根据进程状态的不同,建立几张索引表
- 操作系统持有指向各个索引表的指针
进程的组织——链接方式:
进程的组织——索引方式:
2.1.4、进程的特征:
进程和程序式两个截然不同的概念,相对于程序,进程拥有以下特征:
- 动态性:进程是程序的一次执行过程,是动态的产生、变化和消亡的,是进程的最基本的特征
- 并发性:内存中的多个进程实体,各进程可并发执行
- 独立性:进程是能独立运行、独立获得资源、独立接收调度的基本单位。进程是资源分配、接收调度的基本单位
- 异步性:各进程按各自独立的、不可预知的速度向前推进,操作系统套提供“进程同步机制”来解决异步的问题
- 结构性:每个进程都会配置一个PCB。结构上看,进程由程序段、数据段、PCB组成
2.2、进程的状态和转换
进程的三种基本状态:
- 运行态:占有CPU,并在CPU上运行
- 就绪态:已经具有运行条件,但由于没有空闲CPU,而展示不能运行
- 阻塞态:因等待某一事件而暂时不能运行。
另外两种状态:
- 创建态:进程正在被创建,操作系统为进程分配资源、初始化PCB
- 终止态:进程正在从系统中撤销,操作系统会回收进程拥有的资源,撤销PCB
进程状态的转换
- 就绪态——>运行态:进程被调度
- 运行态——>就绪态:时间片到,或CPU被其他高优先级的进程抢占
- 运行态——>阻塞态:等待系统资源分配,或等待某件事件发生(主动行为)
- 阻塞态——>就绪态:资源分配到尾,等待的事件发生(被动行为)
- 创建态——>就绪态:系统完成创建进程相关的工作
- 运行态——>终止态:进程运行结束,或运行过程中遇到不可修复的错误
2.3、进程控制
2.3.1、进程控制的基本概念
进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程,撤销已有进程、实现进程状态转换等功能。
简化理解:烦着呢个进程控制就是要实现进程状态转换
用原语实现进程控制。原语的特点是执行期间不允许中断,只能一气呵成。
这种不可被中断的操作即原子操作
原语采用“关中断指令”和“开中断指令”实现
显然,关/开中断指令的权限非常大,必然是只允许在核心态下执行的特权指令
2.3.2、进程控制相关的原语
进程的创建:
- 创建原语
- 申请空白PCB
- 为新进程分配所需资源
- 初始化PCB
- 将PCB插入就绪队列
- 引起进程创建的事件
- 用户登录:分时系统中,用户登录成功,系统会将建立为其建立一个新的进程
- 作业调度:多道批处理系统中,有新的作业放入内存时,会为其建立一个新的进程
- 提供服务:用户向操作系统提交某些请求时,会新建一个进程处理该请求
- 应用请求:由用户进程主动请求创建一个子进程
进程的终止:
- 撤销原语
- 从PCB集合中找到终止进程的PCB
- 若程序正在运行,立即剥夺CPU,将CPU分配给其他进程
- 终止其所有子进程
- 将该进程拥有的所有资源归还给父进程或操作系统
- 删除PCB
- 引起进程终止的事件
- 正常结束
- 异常结束
- 外界干预
进程的阻塞和唤醒:阻塞和唤醒要成对的出现
- 进程的阻塞
- 阻塞原语
- 要找到阻塞的进程对应的PCB
- 保护进程运行现场,将PCB状态信息设置为“阻塞态”,暂时停止进程运行
- 将PCB插入相应事件的等待队列
- 引起进程阻塞的事件
- 需要等待系统分配某种资源
- 需要等待相互合作的其他进程完成工作
- 阻塞原语
- 进程的唤醒
- 唤醒原语
- 在事件等待队列中找到PCB
- 将PCB从等待队列中移除,设置进程为就绪态
- 将PCB插入就绪队列,等待被调度
- 引起进程唤醒的事件
- 等待事件的发生,即因何事阻塞,就应该由何事唤醒
- 唤醒原语
进程的切换:
- 切换原语
- 将运行环境信息存入PCB
- PCB移入相应队列
- 选择另一个进程执行,并更新其PCB
- 根据PCB恢复新进程所需的运行环境
- 引起进程切换的事件
- 当前进程时间片到
- 有更高优先级的进程到达
- 当前进程主动阻塞
- 当前进程终止
2.4、进程通信
什么是进程通信?
进程通信指的是进程之间的信息交换
进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立
为了保证安全,一个进程不能直接访问另一个进程的地址空间,但是进程之间的信息交换又是必须实现的,为了保证进程间的安全通信,操作系统提供了一些方法。共享存储、消息传递、管道通信、
2.4.1、共享存储
两个进程对共享空间的访问必须是互斥的
2.4.2、消息传递
进程间的数据交换以格式化的消息为单位。进程通过操作系统提供的“发送消息/接收消息”两个原语进行数据交换
2.4.3、管道通信
“管道”是指用于连接读写进程的一个共享文件,又名pipe文件。其实就是在内存中开辟一个大小固定的缓冲区
- 管道只能采用半双工通信,某一时间段内只能实现单向的传输,如果要实现双向通信,则需要设置两个管道
- 各进程要互斥的访问管道
- 数据以字符流的形式写入管道,当管道写满时,写进程的write()系统调用将被阻塞,等待读进程将数据取走,当读进程将数据全部取走后,管道边控,此时读进程的read()系统调用将被阻塞
- 如果没写满,就不允许读,如果没读空,就不允许写
- 数据一旦被读出,就从管道中被抛弃,这就意味着读进程最毒只能有一个,否则会有读错数据的情况,
2.5、线程机制、多线程模型
引入线程后,线程成为了程序执行流的最小单位。
线程可以理解为“轻量级进程”
线程是一个基本的CPU执行单元,也是程序执行流的最小单位。
引入线程之后,不仅仅是进程之间可以并发,进程内的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种过任务。
引入线程后,进程只作为除CPU之外的系统资源的分配单元。
2.5.1、线程的属性
线程具有以下的属性:
- 线程是处理机调度的单位
- 多个CPU计算机中,多个线程可占用不同的CPU
- 每个线程都有一个线程ID、线程控制块(TCB)
- 线程也有就绪、阻塞、运行三种基本状态
- 线程几乎不拥有系统资源
- 同一进程的不同线程间共享进程的资源
- 由于共享内存地址空间,同一进程中的线程间通信神主无序系统干预
- 同一进程中的线程切换,不会引起进程切换
- 不同进程中的线程切换,会引起进程切换
- 切换同进程内的线程,系统开销很小
- 切换进程,系统开销极大
2.5.2、线程的实现方式
用户级线程:
内核级线程:又称为“内核支持的线程”
在同时支持同户级线程和内核级线程的系统汇总,可采用二者组合的方式:将n个用户级线程映射到m个内核级线程上(n>=m)
内核级线程才是处理机分配的单位!!!
2.5.3、多线程模型
在同时支持用户级线程和内核级线程的系统中,由几个用户级线程映射到几个内核级线程的问题引出了“多线程模型”的问题
多对一模型:
一对一模型:
多对多模型:
小结:
2.6、处理机调度
2.6.1、调度的基本概念
当有一对任务要处理,但由于资源有限,有些事情没法同时处理,这就需要确定某种规则来决定处理这些任务的顺序,这就是“调度”研究的问题。
在多道程序系统中,进程的数量往往是多于处理机的个数的,这样不可能同时地处理各个进程。处理机调度,就是从就绪队列中按照一定的算法按选择一个进程并将处理机分配给它运行,以实现进程的并发执行。
2.6.1.1、调度的三个层次——高级调度:
由于内存空间有限,有时无法将用户提交的作业全部放入到内存,因此就需要确定某种规则来决定将作业调入内存的顺序。
高级调度(作业调度)。按一定的原则从外存上处于后备队列的作业中挑选一个(或多个)作业,给他们分配内存等必要资源,并建立相应的进程(建立PCB),以使他们获得竞争处理机的权利
高级调度是辅存(外存)与内存之间的调度。每个作业只调入一次,调出一次。作业调入时会建立相应的OCB,作业调出时才撤销PCB。高级调度主要是指调入的问题,因为只有调入时机才需要操作系统来确定,调出的事件必然是作业运行结束才调出
2.6.1.2、调度的三个层次——中级调度:
内存不够时,可将某些进程的数据调出外存。等内存空闲或者进程需要运行时再重新调入内存。
暂时调到外存等待的进程状态为挂起状态。被挂起的进程PCB会被组织成挂起队列
中级调度(内存调度)——按照某种策略决定将哪个处于挂起状态的进程重新调入内存。
一个进程可能会被多次调出、调入内存,因此中级调度发生的频率要比高级调度更高
2.6.1.3、调度的三个层次——低级调度:
低级调度(进程调度/处理机调度)—— 按照某种策略从就绪队列中选取一个进程,将处理机分配给它。
进程调度是操作系统中最基本的一种调度,在一般的操作系统中都必须配置进程调度。
进程调度的频率很高,一般几十毫秒一次。
三种调度的对比:
2.6.1.4、进程的挂起态与七状态模型:
暂时调到外存等待的进程状态为挂起状态(挂起态,suspend)
挂起态又可以进一步细分为就绪挂起、阻塞挂起两种状态
五状态模型 ——>七状态模型
小结:
2.6.2、进程调度的时机
进程调度(低级调度),就是按照某种算法从就绪队列中选择一个进程为其分配处理机。
需要进行进程调度与切换的情况:
当前运行的进程主动放弃处理机:进程正常终止、运行过程中发生异常而终止、进程主动请求阻塞(如 等待I/O)
当前运行的进 程被动放弃处理机:分给进程的时间片用完、有更紧急的事需要处理(如 I/O中断)、有更高优先级的进程进入就绪队列
不能进行进程调度与切换的情况:
在处理中断的过程中。中断处理过程复杂,与硬件密切相关,很难做到在中断处理过程中进行进程切换。
进程在操作系统内核程序临界区中。
在原子操作过程中(原语)。原子操作不可中断,要一气呵成(如之前讲过的修改PCB中进程状态标志,并把PCB放到相应队列)
临界资源:一个时间段内只允许一个进程使用的资源。各进程需要互斥地访问临界资源。
临界区:访问临界资源的那段代码。
内核程序临界区一般是用来访问某种内核数据结构的,比如进程的就绪队列(由各就绪进程的PCB组成)
- 如果还没退出临界区(还没解锁就进行进程调度,但是进程调相关的程序也需要访问就绪队列,但此时就绪队列被锁住了,因此又无法顺利进行进程调度
- 内核程序临界区访问的临界资源如果不尽快释放的话,极有可能影响到操作系统内核的其他管理工作。因此在访问内核程序临界区期间不能进行调度与切换
- 在打印机打印完成之前,进程一直处于 临界区内,临界资源不会解锁。但打印 机又是慢速设备,此时如果一直不允许 进程调度的话就会导致CPU一直空闲
- 普通临界区访问的临界资源不会直接影响操作系统内核的管 理工作。因此在访问普通临界区时可以进行调度与切换。
2.6.3、进程调度的切换与过程
“狭义的进程调度”与“进程切换”的区别:
狭义的进程调度指的是从就绪队列中选中一个要运行的进程。(这个进程可以是刚刚被暂停执行的进程, 也可能是另一个进程,后一种情况就需要进程切换)
进程切换是指一个进程让出处理机,由另一个进程占用处理机的过程。
广义的进程调度包含了选择一个进程和进程切换两个步骤。
进程切换的过程主要完成了:
对原来运行进程各种数据的保存
对新的进程各种数据的恢复 (如:程序计数器、程序状态字、各种数据寄存器等处理机现场信息,这些信息一般保存在进程控制块)
注意:进程切换是有代价的,因此如果过于频繁的进行进程调度、切换,必然会使整个系统的效率降低, 使系统大部分时间都花在了进程切换上,而真正用于执行进程的时间减少。
2.6.4、进程调度的方式
- 非剥夺调度方式,又称非抢占方式。即,只允许进程主动放弃处理机。在运行过程中即便有更紧迫 的任务到达,当前进程依然会继续使用处理机,直到该进程终止或主动要求进入阻塞态。
- 实现简单,系统开销小但是无法及时处理紧急任务,适合于早期的批处理系统
- 剥夺调度方式,又称抢占方式。当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,则立即暂停正在执行的进程,将处理机分配给更重要紧迫的那个进程。
- 可以优先处理更紧急的进程,也可实现让各 进程按时间片轮流执行的功能(通过时钟中断)。适合于分时操作系统、实时操作系统
2.7、调度算法
2.7.1、调度算法的评价指标
CPU利用率
系统吞吐量
- 对于计算机来说,希望能用尽可能少的时间处理完尽可能多的作业
- 系统吞吐量:单位时间内完成作业的数量
周转时间
对于计算机的用户来说,他很关心自己的作业从提交到完成花了多少时间。
周转时间,是指从作业被提交给系统开始,到作业完成为止的这段时间间隔。
它包括四个部分:作业在外存后备队列上等待作业调度(高级调度)的时间、进程在就绪队列上等待进程调度(低级调度)的时间、进程在CPU上执行的时间、进程等待I/O操作完成的时间。后三项在一个作业的整个处理过程中,可能发生多次。
(作业)周转时间 = 作业完成时间 – 作业提交时间
等待时间
- 计算机的用户希望自己的作业尽可能少的等待处理机等待时间,指进程/作业处于等待处理机状态时间之和,等待时间越长,用户满意度越低。
- 对于进程来说,等待时间就是指进程建立后等待被服务的时间之和,在等待I/O完成的期间其实进 程也是在被服务的,所以不计入等待时间。
- 对于作业来说,不仅要考虑建立进程后的等待时间,还要加上作业在外存后备队列中等待的时间。
- 一个作业总共需要被CPU服务多久,被I/O设备服务多久一般是确定不变的,因此调度算法其实只会 影响作业/进程的等待时间。当然,与前面指标类似,也有“平均等待时间”来评价整体性能。
响应时间
- 对于计算机用户来说,会希望自己的提交的请求(比如通过键盘输入了一个调试命令)尽早地开始被系统服务、回应。
- 响应时间,指从用户提交请求到首次产生响应所用的时间。
小结:
2.7.2、先来先服务(FCFS)
各种调度算法的学习思路:
算法思想
算法规则
这种调度算法是用于 作业调度 还是 进程调度?
抢占式?非抢占式?
优点和缺点
是否会导致饥饿
2.7.3、最短作业优先(SJF)
严格来说,用于进程调度应该称为短进程优先调度 算法(SPF)
2.7.4、最高响应比优先(HRRN)
FCFS 算法是在每次调度的时候选择一个等待时间最长 的作业(进程)为其服务。但是没有考虑到作业的运行时间,因此导致了对短作业不友好的问题
SJF 算法是选择一个执行时间最短的作业为其服 务。但是又完全不考虑各个作业的等待时间,因此导致了对长作业不友好的问题,甚至还会造成饥饿问题
2.7.5、时间片轮转 (RR, Round-Robin)
如果时间片太大,使得每个进程都可以在一个时间片内就完成,则时间片轮转调度算法退化为先来先服务调度算法,并且会增大进程响应时间。因此时间片不能太大。
另一方面,进程调度、切换是有时间代价的(保存、恢复运行环境),因此如果时间片太小,会导
致进程切换过于频繁,系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比 例减少。可见时间片也不能太小。 比如:系统有10个进程在并发执行,如果时间片为1秒,则一个进程被响应 可能需要等9秒…也就是说,如果用户在自己进程的时间片外通过键盘发出调
2.7.6、优先级调度
非抢占式的优先级调度算法:每次调度时选择当前已到达且 优先级最高的进程。当前进程主动放弃处理机时发生调度。
就绪队列未必只有一个,可以按照不同优先级来组织。另外,也可以把优先级高的进程排在更靠近队头的位置
根据优先级是否可以动态改变,可将优先级分为静态优先级和动态优先级两种。
静态优先级:创建进程时确定,之后一直不变。
动态优先级:创建进程时有一个初始值,之后会根据情况动态地调整优先级。
系统进程优先级 高于 用户进程
前台进程优先级 高于 后台进程
操作系统更偏好 I/O型进程(或称 I/O繁忙型进程)
注:与I/O型进程相对的是计算型进程(或称 CPU繁忙型进程)
可以从追求公平、提升资源利用率等角度考虑 如果某进程在就绪队列中等待了很长时间,则可以适当提升其优先级 如果某进程占用处理机运行了很长时间,则可适当降低其优先级 如果发现一个进程频繁地进行I/O操作,则可适当提升其优先级
2.7.7、多级反馈队列
设置多级就绪队列,各级队列优先级从高到低,时间片从小到大
新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片。若用完时间片进程还 未结束,则进程进入下一级队列队尾。如果此时已经在最下级的队列,则重新放回最下级 队列队尾
只有第 k 级队列为空时,才会为 k+1 级队头的进程分配时间片,被抢占处理机的进程重新放回原队列队尾
2.8、进程同步、互斥
2.8.1、基本概念
读进程和写进程并发地运行,由于并发必然导致异步性,因此“写数据”和“读数据”两个操作执 行的先后顺序是不确定的。而实际应用中,又必须按照“写数据——>读数据”的顺序来执行的。如何解决这种异步问题,就是 “进程同步”所讨论的内容。
同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某 些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作
我们把一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备(比如摄像头、打印机)都属于临界资源。此外还有许多变量、数据、内存缓冲区等都属于临界资源。
对临界资源的访问,必须互斥地进行。互斥,亦称间接制约关系。进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。
什么是进程互斥?
为了实现对临界资源的互斥访问,同时保证系统整体性能,需要遵循以下原则:
空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区;
忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待;
有限等待。对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿);
让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待
小结:
2.8.2、进程互斥的软件实现方法
2.8.2.1、单标志法
单标志法存在的主要问题是:违背“空闲让进”原则。
2.8.2.2、双标志先检查
双标志先检查法的主要问题是:违反“忙则等待”原则。 原因在于,进入区的“检查”和“上锁” 两个处理不是一气呵成的。“检查”后,“上锁”前可能发 生进程切换
2.8.2.3、双标志后检查
因此,双标志后检查法虽然解决了“忙则等待”的问题,但是又违背了“空闲让进”和“有限等待” 原则,会因各进程都长期无法访问临界资源而产生“饥饿”现象。 两个进程都争着想进入临界区,但是谁也不让谁,最后谁都无法进入临界区。
2.8.2.4、Peterson算法
Peterson 算法用软件方法解决了进 程互斥问题,遵循了空闲让进、忙 则等待、有限等待 三个原则,但是依然未遵循让权等待的原则。
Peterson 算法相较于之前三种软件 解决方案来说,是最好的,但依然不够好。
小结:
2.8.3、进程互斥的硬件实现方法
2.8.3.1、中断屏蔽方法
利用“开/关中断指令”实现(与原语的实现思想相同,即在某进程开始访问临界区到结束访问为止都不允许被中断,也就不能发生进程切换,因此也不可能发生两个同时访问临界区的情况)
优点:简单、高效
缺点:不适用于多处理机;只适用于操作系统内核进程,不适用于用户进程(因为开/关中断指令只能运行在内核态,这组指令如果能让用户随意使用会很危险)
2.8.3.2、TestAndSet指令
简称 TS 指令,也有地方称为 TestAndSetLock 指令,或 TSL 指令
TSL 指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。以下是用C语言描述的逻辑
若刚开始 lock 是 false,则 TSL 返回的 old 值为 false,while 循环条件不满足,直接跳过循环,进入 临界区。若刚开始 lock 是 true,则执行 TLS 后 old 返回的值为 true,while 循环条件满足,会一直 循环,直到当前访问临界区的进程在退出区进行“解锁”。
相比软件实现方法,TSL 指令把“上锁”和“检查”操作用硬件的方式变成了一气呵成的原子操作。
优点:实现简单,无需像软件实现方法那样严格检查是否会有逻辑漏洞;适用于多处理机环境
缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从 而导致“忙等”。
2.8.3.3、Swap指令
有的地方也叫 Exchange 指令,或简称 XCHG 指令。
Swap 指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。以下是用C语言描述的逻辑
逻辑上来看 Swap 和 TSL 并无太大区别,都是先记录下此时临界区是否已经被上锁(记录在 old 变 量上),再将上锁标记 lock 设置为 true,最后检查 old,如果 old 为 false 则说明之前没有别的进程,对临界区上锁,则可跳出循环,进入临界区。
优点:实现简单,无需像软件实现方法那样严格检查是否会有逻辑漏洞;适用于多处理机环境
缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从 而导致“忙等”。
小结:
2.9、信号量机制
1965年,荷兰学者Dijkstra提出了一种卓有成效的实现进程互斥、同步的方法——信号量机制
用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥、进程同步。
信号量其实就是一个变量 ,可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为 1 的信号量。
原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现 的。软件解决方案的主要问题是由“进入区的各种操作无法一气呵成”,因此如果能把进入区、退出区的操作都用“原语”实现,使这些操作能“一气呵成”就能避免问题。
一对原语:wait(S) 原语和 signal(S) 原语,可以把原语理解为我们自己写的函数,函数名分别为 wai和 signal,括号里的信号量 S 其实就是函数调用时传入的一个参数。
wait、signal 原语常简称为 P、V操作(来自荷兰语 proberen 和 verhogen)。因此,做题的时候常把wait(S)、signal(S) 两个操作分别写为 P(S)、V(S)
2.9.1、整型信号量
用一个整数型的变量作为信号量,用来表示系统中某种资源的数量。
- 与普通整数变量的区别:对信号量的操作只有三种,即 初始化、P操作、V操作
2.9.2、记录型信号
整型信号量的缺陷是存在“忙等”问题,因此人们又提出了“记录型信号量”,即用记录型数据结构表示的信号量。
2.9.3、信号量实现进程互斥、进程同步和进程的前驱关系
信号量的值 = 这种资源的剩余数量(信号量的值如果小于0,说明此时有进程在等待这种资源)
P( S ) —— 申请一个资源S,如果资源不够就阻塞等待
V( S ) —— 释放一个资源S,如果有进程在等待该资源,则唤醒一个进程
2.9.3.1、进程互斥
分析并发进程的关键活动,划定临界区(如:对临界资源打印机的访问就应放在临界区)
设置互斥信号量 mutex,初值为 1
在进入区 P(mutex)——申请资源
在退出区 V(mutex)——释放资源
对不同的临界资源需要设置 不同的互斥信号量。P、V操作必须成对出现。缺少P(mutex) 就不能保证临界资源的互 斥访问。缺少 V(mutex) 会导致资源永不被释放,等待进程永不被唤醒。
2.9.3.2、进程同步
用信号量实现进程同步:
分析什么地方需要实现“同步关系”,即必须保证“一前一后”执行的两个操作(或两句代码)
设置同步信号量 S, 初始为 0
在“前操作”之后执行 V(S)
在“后操作”之前执行 P(S)
理解:信号量S代表“某种资 源”,刚开始是没有这种资 源的。P2需要使用这种资源, 而又只能由P1产生这种资源
2.9.3.3、进程的前驱关系
小结:
2.9.4、生产者与消费者问题
生产者、消费者共享一个初始为空、大小为n的缓冲区。
只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。
只有缓冲区不空时,消费者才能从中取出产品,否则必须等待。
缓冲区是临界资源,各进程必须互斥地访问。
实现互斥的P操作一定要在实现同步的P操作之后。 V操作不会导致进程阻塞,因此两个V操作顺序可以交换。
易错点:实现互斥和实 现同步的两个P操作的 先后顺序(死锁问题)
2.9.5、多生产者与多消费者问题
问题描述:
问题分析:
问题实现:
即使不设置专门 的互斥变量mutex,也不 会出现多个进程同时访 问盘子的现象
原因在于:本题中的缓冲区大小为1,在任 何时刻,apple、orange、plate 三个同步信 号量中最多只有一个是1。因此在任何时刻, 最多只有一个进程的P操作不会被阻塞,并 顺利地进入临界区…
2.9.6、抽烟者问题
问题描述:
问题分析:
代码实现:
2.9.7、读者——写者问题
问题描述:
问题分析:
问题实现:
2.9.8、哲学家进餐问题
问题描述:
问题分析:
问题实现:
哲学家进餐问题的关键在于解决进程死锁。
这些进程之间只存在互斥关系,但是与之前接触到的互斥关系不同的是,每个进程都需要同时持有 两个临界资源,因此就有“死锁”问题的隐患。
2.9.9、管程
管程是一种特殊的软件模块,有这些部分组成:
局部于管程的共享数据结构说明;
对该数据结构进行操作的一组过程;
对局部于管程的共享数据设置初始值的语句;
管程有一个名字。
管程的基本特征:
局部于管程的数据只能被局部于管程的过程所访问;
一个进程只有通过调用管程内的过程才能进入管程访问共享数据;
每次仅允许一个进程在管程内执行某个内部过程。
引入管程的目的无非就是要更方便地实现进程互斥和同步。
需要在管程中定义共享数据(如生产者消费者问题的缓冲区)
需要在管程中定义用于访问这些共享数据的“入口”——其实就是一些函数(如生产者消费者问题中,可以定义一个函数用于将产品放入缓冲区,再定义一个函数用于从缓冲区取出产品)
只有通过这些特定的“入口”才能访问共享数据
管程中有很多“入口”,但是每次只能开放其中一个“入口”,并且只能让一个进程或线程进 入(如生产者消费者问题中,各进程需要互斥地访问共享缓冲区。管程的这种特性即可保证一 个时间段内最多只会有一个进程在访问缓冲区。注意:这种互斥特性是由编译器负责实现的, 程序员不用关心)
可在管程中设置条件变量及等待/唤醒操作以解决同步问题。可以让一个进程或线程在条件变量 上等待(此时,该进程应先释放管程的使用权,也就是让出“入口”);可以通过唤醒操作将等待在条件变量上的进程或线程唤醒。
程序员可以用某种特殊的语法定义一个管程(比如: monitor ProducerConsumer …… end monitor;),之后其他程序员就可以使用这个管程ᨀ供的特定“入口(封装思想)”很方便地使用实现进程同步/互斥了。
2.10、死锁
2.10.1、死锁的概念
每个人都占有一个资源,同时又在等待另一个人手里的资源。发生“死锁”
在并发环境下,各进程因竞 争资源而造成的一种互相等待对方手里的资源,导致各进程都阻塞,都无法向前推进的现象,就是“死锁”。发生死锁后若无外力干涉, 这些进程都将无法向前推进。
死锁:各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进的现象。
饥饿:由于长期得不到想要的资源,某进程无法向前推进的现象。比如:在短进程优先(SPF)算法中,若有源源不断的短进程到来,则长进程将一直得不到处理机,从而发生长进程“饥饿”。
死循环:某进程执行过程中一直跳不出某个循环的现象。有时是因为程序逻辑 bug 导致的,有时是程序员故意设计的
死锁产生的必要条件:
产生死锁必须同时满足一下四个条件,只要其中任一条件不成立,死锁就不会发生。
互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。 像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待这种资源)。
不剥夺条件:进程所获得的资源在未使用完之前,不能由 其他进程强行夺走,只能主动释放。
请求和保持条件:进程已经保持了至少一个资源,但又提 出了新的资源请求,而该资源又被其他进程占有,此时请 求进程被阻塞,但又对自己已有的资源保持不放。
循环等待条件:存在一种进程资源的循环等待链,链中的 每一个进程已获得的资源同时被下一个进程所请求。
注意!发生死锁时一定有循环等待,但是发生循环等 待时未必死锁(循环等待是死锁的必要不充分条件) 如果同类资源数大于1,则即使有循环等待,也 未必发生死锁。但如果系统中每类资源都只有 一个,那循环等待就是死锁的充分必要条件了。
会产生死锁的情况:
- 对系统资源的竞争。各进程对不可剥夺的资源(如打印机)的竞争可能引起死锁,对可剥夺的资 源(CPU)的竞争是不会引起死锁的。
- 进程推进顺序非法。请求和释放资源的顺序不当,也同样会导致死锁。例如,并发执行的进程P1、P2 分别申请并占有了资源 R1、R2,之后进程P1又紧接着申请资源R2,而进程P2又申请资源R1, 两者会因为申请的资源被对方占有而阻塞,从而发生死锁。
- 信号量的使用不当也会造成死锁。如生产者-消费者问题中,如果实现互斥的P操作在实现同步的P操作之前,就有可能导致死锁。(可以把互斥信号量、同步信号量也看做是一种抽象的系统资源)
总之,对不可剥夺资源的不合理分配,可能导致死锁。
对死锁的处理策略:
- 预防死锁。破坏死锁产生的四个必要条件中的一个或几个。
- 避免死锁。用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法)
- 死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措施解除死锁。
小结:
2.10.2、预防死锁
死锁的产生必须满足四个必要条件,只要其中一个或者几个条件不满足,死锁就不会发生。
破坏互斥条件:
互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁。
该策略的缺点:并不是所有的资源都可以改造成可共享使用的资源。并且为了系统安全,很多地方 还必须保护这种互斥性。因此,很多时候都无法破坏互斥条件。
破坏不剥夺条件
不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
破坏不剥夺条件:
方案一:当某个进程请求新的资源得不到满足时,它必须立即释放保持的所有资源,待以后需要时再重新申请。也就是说,即使某些资源尚未使用完,也需要主动释放,从而破坏了不可剥夺条件。
方案二:当某个进程需要的资源被其他进程所占有的时候,可以由操作系统协助,将想要的资源强行剥夺。这种方式一般需要考虑各进程的优先级(比如:剥夺调度方式,就是将处理机资源强行剥 夺给优先级更高的进程使用)
该策略的缺点:
实现起来比较复杂。
释放已获得的资源可能造成前一阶段工作的失效。因此这种方法一般只适用于易保存和恢复状态 的资源,如CPU。
反复地申请和释放资源会增加系统开销,降低系统吞吐量。
若采用方案一,意味着只要暂时得不到某个资源,之前获得的那些资源就都需要放弃,以后再重新申请。如果一直发生这样的情况,就会导致进程饥饿
破坏请求和保持条件
请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
可以采用静态分配方法,即进程在运行前一次申请完它所需要的全部资源,在它的资源未满足前,不让它投入运行。一旦投入运行后,这些资源就一直归它所有,该进程就不会再请求别的任何资源了。
该策略实现起来简单,但也有明显的缺点:
有些资源可能只需要用很短的时间,因此如果进程的整个运行期间都一直保持着所有资源,就会造成严重的资源浪费,资源利用率极低。另外,该策略也有可能导致某些进程饥饿。
破坏循环等待条件
循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。
可采用顺序资源分配法。首先给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源, 同类资源(即编号相同的资源)一次申请完。
原理分析:一个进程只有已占有小编号的资源时,才有资格申请更大编号的资源。按此规则,已持有大编号资源的进程不可能逆向地回来申请小编号的资源,从而就不会产生循环等待的现象。
该策略的缺点:
不方便增加新的设备,因为可能需要重新分配所有的编号;
进程实际使用资源的顺序可能和编号递增顺序不一致,会导致资源浪费;
必须按规定次序申请资源,用户编程麻烦
小结:
2.10.3、避免死锁
所谓安全序列,就是指如果系统按照这种序列分配资源,则每个进程都能顺利完成。只要能找出一个 安全序列,系统就是安全状态。当然,安全序列可能有多个。
如果分配了资源之后,系统中找不出任何一个安全序列,系统就进入了不安全状态。这就意味着之后可能所有进程都无法顺利的执行下去。当然,如果有进程前归还了一些资源,那系统也有可能重新回到安全状态,不过我们在分配资源之前总是要考虑到最坏的情况。
如果系统处于安全状态,就一定不会发生死锁。如果系统进入不安全状态,就可能发生死锁(处于不 安全状态未必就是发生了死锁,但发生死锁时一定是在不安全状态) 因此可以在资源分配之前预先判断这次分配是否会导致系统进入不安全状态,以此决定是否答应资源分配请求。这也是“银行家算法”的核心思想。
银行家算法:
银行家算法是荷兰学者 Dijkstra 为银行系统设计的,以确保银行在发放现金贷款时,不会发生不能 满足所有客户需要的情况。后来该算法被用在操作系统中,用于避免死锁。
核心思想:在进程ᨀ出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进 入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待。
数据结构:
长度为 m 的一维数组 Available 表示还有多少可用资源
n*m 矩阵 Max 表示各进程对资源的最大需求数
n*m 矩阵 Allocation 表示已经给各进程分配了多少资源
Max – Allocation = Need 矩阵表示各进程最多还需要多少资源
用长度为 m 的一位数组 Request 表示进程此次申请的各种资源数
银行家算法步骤:
检查此次申请是否超过了之前声明的最大需求数
检查此时系统剩余的可用资源是否还能满足这次请求
试探着分配,更改各数据结构
用安全性算法检查此次分配是否会导致系统进入不安全状态
安全性算法步骤:
检查当前的剩余可用资源是否能满足某个进程的最大需求,如果可以,就把该进程加入安全序列,并把该进程持有的资源全部回收。
不断重复上述过程,看最终是否能让所有进程都加入安全序列。
2.10.4、死锁的检测与解除
如果系统中既不采取预防死锁的措施,也不采取避免死锁的措施,系统就很可能发生死锁。在这种 情况下,系统应当提供两个算法:
死锁检测算法:用于检测系统状态,以确定系统中是否发生了死锁。
死锁解除算法:当认定系统中已经发生了死锁,利用该算法可将系统从死锁状态中解脱出来
死锁的检测:
为了能对系统是否已发生了死锁进行检测,必须:
用某种数据结构来保存资源的请求和分配信息;
提供一种算法,利用上述信息来检测系统是否已进入死锁状态。
最终还连着边的那些进程就是处于死锁状态的进程。
检测死锁的算法:
在资源分配图中,找出既不阻塞又不是孤点的进程 Pi(即找出一条有向边与它相连,且该有向边对应资源的申请数量小于等于系统中已有空闲资源数量。如下图中,R1没有空闲资源,R2有个空闲资源。若所有的连接该进程的边均满足上述条件,则这个进程能继续运行直至完成,然 后释放它所占有的所有资源)。消去它所有的请求边和分配变,使之称为孤立的结点。在图中P1 是满足这一条件的进程结点,于是将P1的所有边消去。
进程 Pi 所释放的资源,可以唤醒某些因等待这些资源而阻塞的进程,原来的阻塞进程可能变为非阻塞进程。在图中,P2 就满足这样的条件。根据 1)中的方法进行一系列简化后,若能消去途中所有的边,则称该图是可完全简化的
死锁定理:如果某时刻系统的资源分配图 是不可完全简化的,那么此时系统死锁
死锁的解除:
一旦检测出死锁的发生,就应该立即解除死锁。
补充:并不是系统中所有的进程都是死锁状态,用死锁检测算法化简资源分配图后,还连着边的那些进程就是死锁进程
解除死锁的主要方法有:
资源剥夺法。挂起(暂时放到外存上)某些死锁进程,并抢占它的资源,将这些资源分配给 其他的死锁进程。但是应防止被挂起的进程长时间得不到资源而饥饿。
撤销进程法(或称终止进程法)。强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资 源。这种方式的优点是实现简单,但所付出的代价可能会很大。因为有些进程可能已经运行 了很长时间,已经接近结束了,一旦被终止可谓功亏一篑,以后还得从头再来。
进程回退法。让一个或多个死锁进程回退到足以避免死锁的地步。这就要求系统要记录进程的历史信息,设置还原点
如何决定“对谁下手”:
进程优先级
已执行多长时间
还要多久能完成
进程已经使用了多少资源
进程是交互式的还是批处理式的
-------------本文结束感谢您的阅读-------------
本文链接: http://example.com/2020/11/04/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%EF%BC%88%E4%B8%80%EF%BC%89/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!