王道操作系统个人向笔记-第二章
2.1 进程
2.1.1 进程的概念、组成、特征
- 程序:是静态的,存放再磁盘里的可执行文件,是一系列的指令集合
- 进程:是动态的,是程序的一次执行过程
- 进程的组成(PCB)
- 当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的“身份中号PID(Process ID)”
- 操作系统记录有关进程的信息都被保存在一个数据结构PCB(Process Control Block)中,即进程控制块
- 程序段:是能被进程调度程序调度到CPU执行的程序代码段。程序可被多个进程共享,即多个进程可以运行同一个程序
- 数据段:包含运行过程中产生的各种数据
一个进程实体(进程映像)由PCB、程序段、数据段组成,进程是动态的,进程实体(进程映像)是静态的
2.1.2 进程的状态与转换
进程正在被创建时,它的状态时“创建态”,在这个阶段操作系统会为进程分配资源、初始化PCB
当进程创建完成后,便进入“就绪态”,处于就绪态的进程已经具备运行条件,但由于没有空闲CPU,就暂时不能运行
当CPU空闲时,操作系统就会选择一个就绪进程让它上处理机运行,如果一个进程此时在CPU上运行,那么这个进程处于“运行态”,CPU会执行该进程对应的程序(执行指令序列)
在进程运行的过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其他进程的响应)在这个事件发生之前,进程无法继续往下执行,此时操作系统会让这个进程下CPU,并让他进入阻塞态
一个进程可以执行exit系统调用,请求操作系统终止该进程。此时该进程会进入终止态,操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB,当终止进程的工作完成之后,这个进程就彻底消失了
进程五状态模型
进程PCB中,会有一个变量state来表示进程的当前状态。
进程的组织--链接方式
进程的组织--索引方式
2.1.3 进程控制
进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能
简单点理解:进程控制就是实现进程状态转换
原语
:是一种特殊的程序,它的主席那个具有原子性,这段程序的运行必须一气呵成,不可中断。原语的执行具有原子性,即执行过程中只能一气呵成,期间不允许被中断。
可以用关中断指令和开中断指令,这两个特权指令
实现原子性
进程控制相关的原语
-
进程的创建
-
进程的终止
-
进程的阻塞和唤醒
-
进程的切换
2.1.4 进程通信IPC
进程间通信(Inter-Process Communication,IPC)是指两个进程之间产生数据交互
为什么进程通信需要操作系统支持
进程是分配系统资源的单位,因此各进程拥有的内存地址空间相互独立
共享存储
共享存储有两种
- 基于存储区的共享:操作系统在内存中划出一块共享存储区,数据的形式和存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式
- 基于数据结构的共享:比如共享空间只能放一个长度为10的数组,这种共享方式速度慢,限制多,是一种低级通信方式
消息传递
进程间的数据交换一格式化的消息(Message)为单位,进程通过操作系统提供的“发送消息/接受消息”两个原语进行数据交换
格式化的消息
:
消息传递又可以划分为:直接通信方式和间接通信方式
管道通信
半双工通信
管道是一个特殊的共享文件,又名pipe文件,其实就是在内存中开辟一个大小固定的内存缓冲区
数据读写的特性是FIFO
注意和共享存储的通信方式的区别:
共享存储很自由没有什么限制
管道通信是一个数据流的形式,读写顺序有限制
- 管道只能采用半双工通信,某一时间段内只能实现单向的传输。如果要实现双向同时通信,则需设置两个管道
- 各进程要互斥地访问管道(由操作系统实现)
- 当管道写满时,写进程将阻塞,知道读进程将管道中的数据取走,即可唤醒写进程
- 当管道读空时,读进程将阻塞,知道写进程往管道中写入数据,即可唤醒读进程。
- 管道中的数据一旦被读出,就彻底消失,因此,当多个进程读同一各管道时,可能会错乱。
2.2 线程
2.2.1 线程的概念
可以把线程理解为“轻量级进程”
线程是一个基本的CPU执行单元,也是程序执行流的最小单元。
引入线程之后,不仅是进程之间可以并发,进程内的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种任务(如qq视频、文字聊天、传文件)
引入线程后,进程只作为除CPU之外的系统资源的分配单元
引入线程机制后的变化
2.2.2 线程的实现方式
线程的实现方式有用户级线程和内核级线程。
用户级线程(User-Level Thread,ULT)
:早期的操作系统只支持进程,不支持线程
- 用户级线程由应用程序通过线程库实现,所有的线程管理工作都由应用程序负责(包括进程的切换)
- 用户级线程中,线程切换可以在用户态下即可完成,无需操作系统干预。
- 在用户看来,是有多个线程,但是在操作系统内核看来,并意识不到线程的存在
用户级线程就是从用户视角能看到的线程
优缺点
优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高,多个线程不可再多核处理机上并行运行。
内核级线程(Kernel-Level Thread,KLT,又称内核支持的线程)
- 内核级线程的管理工作由操作系统内核完成
- 线程调度、切换等工作都由内核负责,因此内核级线程的切换必然需要再和心态下才能完成。
- 操作系统会为每个内核级线程建立相应的TCB(Thread Control Block,线程控制块),通过TCB对线程进行管理。内核级线程就是从操作系统内核视角看能看到的线程
- 优缺点
- 优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可再多核处理机上并行执行。
- 缺点:一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大。
多线程模型
2.2.3 线程的状态与转换
2.3 调度
2.3.1 调度的概念、层次
当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规划来决定处理这些任务的顺序,这就是调度研究的问题。
调度的三个层次
作业
:一个具体的任务(用户向系统提交一个作业=用户让操作系统启动一个程序来处理一个具体的任务)
高级调度(作业调度)
:按一定的原则从外存的作业后备队列中挑选一个作业调入内存,并创建进程,每个作业之调入一次,调出一次。作业调入时会建立PCB,调出时才撤销PCB。
低级调度(进程调度/处理机调度)
:按照某种策略从就绪队列中选取一个进程,将处理机分配给它
中级调度(内存调度)
:按照某种策略决定将哪个处于挂起状态的进程重新调入内存
暂时调到外存等待的进程状态为挂起状态
2.3.2 进程调度的时机、切换与过程调度方式
进程调度(低级调度):按照某种算法从就绪队列中选择一个进程为其分配处理机。
when?
两种情况需要进行进程调度与切换:
- 当前运行的进程主动放弃处理机
- 当前运行的进程被动放弃处理机
不能进行进程调度与切换的情况
- 在处理中断的过程中
- 进程在操作系统内核临界区中
- 在原子操作过程中(原语)
临界资源:一个时间段内只允许一个进程使用的资源,各进程需要互斥地访问临界资源
内核程序临界区:一般是用来访问某种内核数据结构的,比如进程的就绪队列(由各就绪进程的PCB组成)
进程调度的方式
- 非剥夺调度方式,又称非抢占方式。即,只允许进程主动放弃处理机。在运行过程中即便有更紧迫的任务到达,当前进程依然会继续使用处理机,直到该进程终止或主动要求进入阻塞态。
特点:实现简单,系统开销小,但是无法及时处理紧急任务,适合于早期的批处理系统 - 剥夺调度方式,又称抢占方式。当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,则立即暂停正在执行的进程,将处理机分配给更重要紧迫的那个进程
特点:可以优先处理更紧急的进程,也可以实现让各进程按时间片轮流执行的功能(通过时钟中断)。适合于分时操作系统、实时操作系统
狭义的进程调度与进程切换的区别
狭义的进程调度指的是从就绪队列中选中一个要运行的进程。(这个进程可以是刚刚被暂停执行的进程,也可能是另一个进程,后一种情况就需要进程切换)
进程切换是指一个进程让出处理机,由另一个进程占用处理机的过程
广义的进程调度包含选择一个进程和进程切换两个步骤
进程切换的过程主要完成了
- 对原来运行进程各种数据的保存
- 对新的进程各种数据的恢复(如:程序计数器、程序状态字、各种数据寄存器等处理机现场信息,这些信息一般保存在进程控制块)
注意:进程切换是有代价的,因此如果过于频繁的进行进程调度、切换,必然会使整个系统的效率降低,使系统大部分时间都花在了进程的切换上,而真正用于执行进程的时间减少
2.3.3 调度器和闲逛进程
2和3由调度程序引起、调度程序决定
调度时机?:
- 创建新进程
- 进程退出
- 运行进程阻塞
- I/O中断发生(可能唤醒某些阻塞进程)
非抢占式调度策略,只有运行进程阻塞或退出才会出发调度程序工作
抢占式调度策略,每个时钟中断或k各时钟中断会出发调度程序工作
闲逛进程:调度程序永远的备胎,没有其他就绪进程时,运行闲逛进程(idle)
2.3.4 调度算法的评价指标
- cpu利用率:指cpu忙碌的时间占总时间的比例
\(利用率=\frac{忙碌的时间}{总时间}\) - 系统吞吐量:单位时间内完成的作业数量
\(系统吞吐量=\frac{总共完成了多少道作业}{总共花了多少时间}\) - 周转时间:指从作业被提交给系统开始,到作业完成为止的这段时间间隔。
它包括四个部分:作业在外存后备队列上等待作业调度(高级调度)、进程在就绪队列上等待进程调度(低级调度)的时间、进程在cpu上执行的时间、进程等待I/O操作完成的时间。后三项在一个作业的整个处理过程中,可能发生多次
\((作业)周转时间=作业完成时间-作业提交时间\)
\(平均周转时间=\frac{各作业周转时间之和}{作业数}\) - 带权周转时间
\(带权周转时间=\frac{作业周转时间}{作业实际运行的时间}=\frac{作业完成时间-作业提交时间}{作业实际运行的时间}\)
带权周转时间更小,用户满意度更高 - 等待时间
计算机的用户希望自己的作业尽可能少的等待处理机。
等待时间指进程/作业处于等待处理机状态时间之和,等待时间越长,用户满意度越低
- 相应时间:指用户提交请求到首次产生响应所用的时间
2.3.5 调度算法1 (适用于批处理系统)
先来先服务调度算(FCFS):按照到达的先后顺序调度,事实上就是等待时间越久的越优先得到服务
短作业优先(SJF, shortest Job First):最短的作业优先得到服务
非抢占式短作业优先
抢占式短作业优先算法
高响应比优先(HRRN):
综合考虑作业/进程的等待时间和要求服务的时间
\(响应比=\frac{等待时间+要求服务时间}{要求服务时间}\)
2.3.6 调度算法2 (使用与交互式系统)
时间片轮转
优先级调度算法
优先级调度算法有抢占式和非抢占式
多级反馈队列调度算法“
2.3.7 调度算法3
多级队列调度算法
系统中按进程类型设置多个队列,进程创建成功后插入某个队列
2.4 同步与互斥
2.4.1 进程同步、进程互斥
进程具有异步性的特征。异步性是指,各并发执行的进程以各自独立的、不可预知的速度向前推进。
进程同步所讨论的内容就是如何解决异步问题
同步也称为直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于他们之间的相互合作
进程的并发需要共享的支持,各个并发执行的进程不可避免的需要共享一些系统资源(比如内存、又比如打印机、摄像头这样的I/O设备)
我们把一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备(比如摄像头、打印机)都属于临界资源。此外还有许多变量、数据、内存缓冲区等都属于临界资源。
对临界资源的访问,必须互斥地进行。互斥,亦称间接制约关系。进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。
对临界资源的互斥访问,可以在逻辑上分为如下四个部分
do{
entry section; //进入区
critical section; //临界区
exit section; //推出去
remainder section; //剩余区
}while(true)
- 进入区:负责检查是否可进入临界区,若可进入,则应设置正在访问临界资源标志(可以理解为上锁),以阻止其他进程同时进入临界区
- 临界区:访问临界资源的那段代码
- 退出区:负责解除正在访问临界资源的标志(可理解为解锁)
- 剩余区:做其他处理
进入区
和退出区
是负责实现互斥的代码段,临界区
是进程中访问临界资源的代码段,临界区也可称为临界段
为了实现对临界资源的互斥访问,同时保证系统整体性能,需要遵循以下原则:
- 空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区
- 忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待
- 有限等待。对请求访问的进程,应保证能在有限时间进入临界区(保证不会饥饿)
- 让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。
2.4.2 进程互斥的软件实现方法
- 单标志法
算法思想:两个进程在访问玩临界区后会把使用临界区的权限转交给另一个进程。也就是说每个进程进入临界区的权限只能被另一个进程赋予。
违背空闲让进的原则 - 双标志先检查法
算法思想:设置一个布尔型数组flag[],数组中各个元素用来标记各进程想进入临界区的意愿,比如flag[0]=true意味着0号进程\(p_0\)现在想要进入临界区。每个进程在进入临界区之前先检查有没有别的进程想进入临界区,如果没有,则把自身对应的标志flag[i]设置为true,之后开始访问临界区
bool flag[2]; //表示进入临界区意愿的数组
flag[0]=false;
flag[1]=false; //刚开始设置为两个进程都不想进入临界区
违反了忙则等待的原则,原因在于,进入区的检查和上锁两个处理过程不是一气呵成的。
3. 双标志后检查法
算法思想:双标志先检查法的改版。前一个算法的问题是先检查后上锁,但是这两个操作又无法一气呵成,因此导致了两个进程同时进入临界区的问题。因此,人们又想到先上锁后检查的方法,来避免上述问题。
双标志检查法虽然解决了忙则等待的问题,但是又违背了空闲让进和有限等待原则,会因各进程都长期无法访问临界资源而产生饥饿现象。
4. Peterson算法
算法思想:结合双标志法、单标志法的思想。如果双方都争着想进入临界区,那可以让进程尝试孔融让梨。做一个有礼貌的进程。
谁最后让,就是另一个人先用。
没有遵循让权等待的原则。
2.4.3 进程互斥的硬件实现方法
- 中断屏蔽方法
利用”开/关中断指令“实现
优点:简单、高效
缺点:不适用于多处理机;只适用于操作系统内核进程,不适用于用户进程(因为开关中断指令只能运行在内核态,这组指令如果能让用户随意使用会很危险) - TestAndSet指令
简称TS指令,也称TestAndSetLock指令或TSL指令
TSL指令使用硬件实现的,执行过程中不允许被中断,只能一气呵成。
以下是用c语言秒速的逻辑
上面c语言实现的只是逻辑,实际上这些都是由硬件实现的
- Swap指令
有的地方也叫Exchange指令,或简称XCHG指令。
Swap指令使用硬件实现的,执行的过程中不允许被中断,只能一气呵成。以下使用c语言秒速的逻辑
2.4.4 进程互斥:锁
解决临界区最简单的工具就是互斥锁(mutex lock)一个进程在进入临界区时应获得锁;在退出临界区时释放锁。函数acquire()获得锁,而函数release()释放锁。
每个互斥锁有一个布尔变量available,表示锁是否可用。如果锁是可用的,调用acqiure()会成功,且锁不再可用。当一个进程试图获取不可用的锁时,会被阻塞,直到锁被释放。
特性:
- 需要忙等,进程时间片用完才下处理机,违反让权等待
- 优点:等待期间不需要切换进程上下文,多处理器系统中,若上锁时间段,则等待代价很低
- 常用于多处理器系统,一个核忙等,其他核照常工作,并快速释放临界区
- 不太使用于单处理机系统,忙等的过程中不可能解锁
2.4.5 信号量机制
用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现进程互斥、进程同步
信号量:一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量,比如:系统中由一台打印机,就可以设置一个初值为1的信号量
原语:一种特殊的程序段,其执行只能一气呵成不可被中断,原语是由关中断/开中断指令实现的,软件解决方案的主要问题是由进入区的各种操作无法一气呵成,因此如果能把进入区、推出去的操作都用原语实现,使这些操作能一气呵成就能避免问题
一对原语:wait(S)原语和signal(S)原语,可以把原语理解为我们自己写的函数,函数名分别为wait和signal,括号里的信号量S其实就是函数调用时传入的一个参数
wait、signal原语常简称为P、V操作。因此,常把wait(S)、signal(S)两个操作分别写为P(S)、V(S)
- 整型信号量
用一个整数型的变量作为信号量,用来表示系统中某种资源的数量
- 记录型信号量
整型信号量的缺陷是存在忙等问题,因此人们又提出了”记录型信号量“,即用记录型数据结构表示的信号量
wait原语
signal原语
2.4.5 信号量机制实现同步、互斥、前驱关系
信号量机制实现互斥
- 分析并发进程的关键活动,划定临界区
- 设置互斥信号量mutex,初值为1
- 在进入区P(mutex)申请资源
- 在退出区V(mutex)释放资源
mutex可以理解为“进入临界区的名额”
信号量机制实现进程同步
进程同步:要让各个并发进程按要求有序地推进。
用信号量实现进程同步:
- 分析什么地方需要实现同步关系,即必须保持一前一后执行的两个操作
- 设置同步信号量S,初始为0
- 在前操作之后执行V(S)
- 在后操作之间执行P(S)
口诀:前V后P
信号量机制实现前驱关系
生产者消费者问题
系统中有一组生产者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用(这里的产品理解为某种数据)生产者、消费者共享一个初始为空、大小为n的缓冲区。
只有缓冲区没满时,生产者才能把产品放入缓冲区否则必须等待。
只有缓冲区不空时,消费者才能从中取出产品,否则必须等待。
缓冲区是临界资源,各进程必须互斥地访问。
PV操作题目分析步骤:
- 关系分析。找出题目中描述的各个进程,分析它们之间的同步、互斥关系。
- 整理思路。根据各进程的操作流程确定P、V操作的大致顺序。
- 设置信号量。并分局题目条件确定信号量初值。(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)
多生产者多消费者
没有互斥信号量也可以实现互斥
吸烟者问题
读者写者问题
增加了信号量w解决了饥饿问题
读者写者问题为我们解决复杂的互斥问题提供了一个参考思路,其核心思想在于设置了一个计数器count用来记录当前正在访问共享文件的进程数,我们可以用count的值来判断当前进入的进程是否是第一个/最后一个读进程,从而做出不同的处理。
另外吗,对count的检查和赋值不能一气呵成导致了一些错误,如果需要实现一气呵成,自然应该想到用互斥信号量。
哲学家进餐问题
- 关系分析。系统中有5个哲学家进程,5位哲学家与左右邻居对其中间筷子的访问时互斥关系
- 整理思路。这个问题中只有互斥关系,但与之前遇到的问题不同是,每个哲学家进程需要同时持有两个临界资源才能开始吃。如何避免临界资源分配不当造成死锁现象,时哲学家问题的精髓
- 信号量设置。定义互斥信号量数组
chopstick[5]={1,1,1,1,1}用于实现对5个筷子的互斥访问。并对哲学家按0~4号编号,哲学家i的左边的筷子编号为i,右边的筷子编号为(i+1)%5
上面代码可能造成死锁。
如何防止死锁的发生?
- 可以对哲学家进程施加一些限制条件,比如最多允许四个哲学家同时进餐。这样可以保证至少有一个哲学家是可以拿到左右两只筷子的
- 要求奇数号哲学家先拿左边的筷子,然后才能拿右边的筷子,而偶数号哲学家刚好相反,用这种方法可以保证如果相邻的两个奇偶号哲学家都想吃饭,那么只会有其中一个可以拿起一只筷子,另一个会直接阻塞。这就避免了占有一只筷子再等待另一只的情况
- 仅当一个哲学家左右两边的筷子都可以使用时才让他抓起筷子
管程
信号量机制存在的问题:编写程序困难、易出错
管程是一种高级的同步机制
管程是一种特殊的软件模块,有这些部分组成了:
- 局部于管程的共享数据结构说明
- 对该数据结构进行操作的一组过程
- 对局部于管程的共享数据设置初始值的语句
- 管程有一个名字。
管程的基本特征:
- 局部于管程的数据智能被局部于管程的过程所访问
- 一个进程只有通过调用管程内的过程才能进入管程访问共享数据
- 每次仅允许一个进程在管程内执行某个内部过程
2.5 死锁
2.5.1 死锁的概念
各种进程因竞争资源而造成的一种互相等待对方手里的资源,导致进程都阻塞,都无法向前推进的现象,就是死锁。
各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推荐的现象。
饥饿:由于长期得不到想要的资源,某进程无法向前推进的现象。比如:在短进程优先(SPF)算法中,若有源源不断的短进程到来,则长进程将一直得不到处理机,从而发生长进程饥饿。
死循环:某进程执行过程中一直挑不出某个循环的现象。有时是因为程序逻辑bug导致的,有时是程序员故意设计的。
解决死循环根本不是操作系统需要解决的问题。
死锁产生的必要条件
产生死锁必须同时满足四个条件:
- 互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待这种资源)
- 不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,智能主动释放
- 请求和保持条件:进程已经保持了至少一个资源,但是又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
- 循环等待条件:存在一种进程资源的循环等待链。链中的每一个进程已获得的资源同时被下一个进程所请求。
死锁的处理策略
- 预防死锁。破坏死锁产生的四个必要条件中的一个或几个。
- 避免死锁。用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法)
- 死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措施解除死锁。
2.5.2 预防死锁
破坏死锁产生的四个必要条件中的一个或者几个条件
互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁
不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
破坏不剥夺条件
破坏请求和保持条件
破坏循环等待条件
顺序资源编号分配法:首先给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源,同类资源(即编号相同的资源)一次申请完。
原理分析:一个进程只有已占有小编号的资源时,才有资格申请更大编号的资源。按此规则,已持有大编号资源的进程不可能逆向地回来申请小编号资源,从而就不会产生循环等待现象
2.5.3 避免死锁
安全序列
所谓安全序列,就是指如果系统按照这种序列分配资源,则每个进程都能顺利完成。只要能找出一个安全序列,系统就是安全状态,当然,安全序列可能有多个。
如果分配了资源之后,系统中找不出任何一个安全序列,系统就进入了不安全状态,这就意味着之后可能所有进程都无法顺利执行下去。当然,如果有进程提前归还了一些资源,拿系统也有可能重新回到安全状态,不过我们在分配资源之前总是要考虑到最坏的情况。
如果系统处于安全状态,就一定不会发生死锁。如果系统进入不安全状态,就可能发生死锁(处于不安全状态未必就是发生了死锁,但发生了死锁西戎一定是处在不安全状态)
因此,可以在资源分配之前预先判断这次分配是否会导致系统进入不安全状态,以此决定是否答应资源分配请求。这也是银行家算法的核心思想。
银行家算法:由荷兰学者Dijkstra为银行系统设计的,以确保银行在发放现金贷款时,不会发生不能满足所有客户需要的情况,后来该算法被用在操作系统中,用于避免死锁。
核心思想:在进程提出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待。
2.5.4 死锁的检测和解除
如果系统中既不采取预防死锁的措施,也不采取避免死锁的措施,系统就很可能发生死锁。在这种情况下,系统应当提供两个算法。
- 死锁检测算法:用于检测系统状态,以确定系统中是否发生了死锁。
- 死锁解除算法,当认定系统中已经发生了死锁,利用该算法可将系统从死锁状态中解脱出来
死锁检测算法:
数据结构:资源分配图
如果系统中剩余的可用资源数足够满足进程的需求,南无这个进程暂时是不会阻塞的,可以顺利地执行下去。响应的,这些被激活的进程执行完了之后又会归还一些资源,这样可能会激活另外一些阻塞的进程
如果按上述过程分析,最终能消除所有边,就称这个图是可完全简化的。此时一定没有发生死锁
死锁的解除