一、进程与线程
1. 进程
程序:是静态的,就是个存放在磁盘里的可执行文件,就是一系列的指令集合。
进程(Process):是指计算机中已执行的程序,是动态的。
(1)进程的组成
当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的编号,即进程ID(Process ID,PID),操作系统此时要记录PID。除此之外,操作系统还需要记录进程所属用户ID(UID)、给进程分配的资源、进程的运行情况等。
这些信息都被保存在一个数据结构 进程控制块(Process Control Block,PCB ) 中,操作系统需要对各个并发运行的进程进行管理,但凡管理时所需要的信息,都会被放在PCB中。
PCB是进程存在的唯一标志,当进程被创建时,操作系统为其创建PCB,当进程结束时,会回收其PCB。
除了PCB,进程还需要程序段来存放程序的代码,并使用 数据段 保存进程执行时产生的数据(如程序中定义的变量)。
一个进程实体(进程映像)由PCB、程序段、数据段组成。其中程序段用来存放程序的代码(指令), 数据段 用来保存进程执行时产生的数据。
进程是动态的,进程实体(进程映像)是静态的。进程实体反应了进程在某一时刻的状态(如:x++后,x=2)
程序运行示意图:
(2)进程的特征
程序是静态的,进程是动态的,相比于程序,进程拥有以下特征。
-
动态性:进程是程序的一次执行,经历创建、活动、暂停、终止等过程,具有一定的生命周期,是动态产生、变化和消亡的基本特征。
-
并发性:多个进程实体能够同时存在于内存中,在一段时间内同时运行,提高资源利用率,并发性是进程的重要特征,也是操作系统的关键特征。
-
独立性:进程实体是一个能够独立运行、独立获取资源和独立接受调度的基本单位。未建立PCB的程序无法作为独立单位参与运行。
-
异步性:由于进程相互制约,导致执行间断性,进程按照各自独立且不可预知的速度向前推进,需配置进程同步机制以处理异步性带来的挑战。
-
结构性:每个进程通过PCB进行描述,包含程序段、数据段和进程控制块三部分组成。这种结构性有助于管理和控制进程的执行和状态转换。
(3)多个进程之间的PCB组织方式
在一个系统中,通常会存在成百上千个PCB。为了有效管理它们,需要采取适当的方式来组织这些PCB。
进程的PCB组织方式包括链接方式和索引方式。
-
链接方式:在链接方式中,每个进程的PCB包含一个指向下一个PCB的指针,形成一个链表结构。当系统需要访问某个特定进程的PCB时,可以顺着链表依次查找直到找到目标PCB。这种方式适合于需要频繁插入和删除进程的情况,但可能会增加查找时间。
-
索引方式:在索引方式中,系统维护一个索引表,其中记录了所有进程PCB的位置信息或关键字,通过索引表可以直接查找到对应进程的PCB。这种方式可以提高查找效率,适合于需要快速访问进程PCB的情况。
选择使用链接方式还是索引方式取决于系统的需求和设计考虑,不同的方式各有优劣,可以根据具体情况进行选择。
2. 进程的状态
(1)进程的五种状态
进程在操作系统中通常有五种状态,包括:
-
创建态(new):进程被创建时处于“创建态”状态,操作系统为其分配资源并初始化PCB,为进程的正常运行做准备。
-
就绪态(Ready):创建完成后,进程进入“就绪态”,表示它已经准备好运行,但由于没有空闲CPU,暂时无法执行。
-
运行态(Running):当进程获得CPU时间并开始执行对应的程序指令时,处于“运行态”,CPU会按照指令序列执行该进程。
-
阻塞态(Blocked / Waiting):在执行过程中,进程可能因等待某事件发生而无法继续执行,此时进程会进入“阻塞态”,操作系统会让其释放CPU,并等待事件发生。当CPU空闲时,操作系统会选择另一个“就绪态”进程继续执行。
-
终止态(Terminated):进程通过调用exit系统调用请求终止时,进入“终止态”,操作系统回收资源、释放内存空间等,并最终销毁该进程。一旦终止完成,进程从系统中彻底消失。
其中就绪态(Ready)、运行态(Running)、阻塞态(Blocked)为进程的三种基本状态。
(2)进程状态的转换
下面是对进程状态转换的简要描述:
-
NULL → 新建态:执行一个程序,创建一个子进程,进程从NULL状态转变为新建态。
-
新建态 → 就绪态:当操作系统完成了进程创建的必要操作,并且系统性能和虚拟内存容量允许时,进程从新建态转变为就绪态,表示已准备好运行但暂时无法执行。
-
运行态 → 终止态:当进程达到自然结束点、出现无法解决的错误、被操作系统或其他有终止权的进程终结时,进程从运行态转为终止态。
-
运行态 → 就绪态:当进程的运行时间片用完或出现更高优先级的进程时,进程从运行态转为就绪态等待重新调度。
-
运行态 → 等待态:进程等待使用资源(如外设传输),需要等待人工干预或其他事件发生时,进程从运行态转为等待态。
-
就绪态 → 终止态:在某些操作系统中,未在状态图中显示,但父进程可能允许终结子进程,此时进程从就绪态直接转为终止态。
-
等待态 → 终止态:和上一条类似,在某些操作系统中,虽未在状态图中显示,但允许父进程终结子进程,进程从等待态直接转为终止态。
-
终止态 → NULL:进程完成所有清理工作后,从终止态返回到NULL状态,整个进程生命周期结束。
3.进程的控制
进程控制的主要功能是对系统中所有进程进行有效管理,包括创建新进程、撤销已有进程和实现进程状态转换等。操作系统中通常将用于进程控制的程序段称为原语,其特点是在执行期间不允许中断,是一个不可分割的基本单位。原语的不可中断性确保了进程控制操作的完整性和一致性,防止出现竞争条件和数据不一致的情况,从而提高了系统的稳定性和可靠性。
进程的创建、终止、阻塞和唤醒是进程控制中的重要过程,它们包括以下步骤:
-
创建进程:
- 为新进程分配一个唯一的进程标识号,并为进程分配空白的PCB,并填写控制和管理信息,若PCB申请失败,则进程创建失败。
- 为进程分配资源,为新进程的程序和数据及用户栈分配必要的内存空间(在PCB 中体现)。若资源不足(如内存空间),则处于阻塞态,等待内存资源;
- 将PCB插入就绪队列,等待调度执行。
-
终止进程:
- 查找要终止的进程的PCB。
- 如果进程正在执行,立即终止其执行,并释放CPU资源。
- 如果进程有子进程,将子进程交给父进程或由1号进程(init)接管。
- 归还进程拥有的资源给操作系统,从PCB队列中删除该进程。
-
阻塞进程:
- 找到需要阻塞的进程的标识对应的PCB。
- 如果进程正在运行,保护其现场,将状态转换为阻塞状态,暂停运行。
- 将PCB插入阻塞队列中。
-
唤醒进程:
- 在阻塞队列中找到相应事件的阻塞进程的PCB。
- 将其移出阻塞队列,并设置为就绪状态。
- 将PCB插入就绪队列,等待调度程序调度运行。
进程的阻塞和唤醒是进程控制中重要的操作,确保进程间的合理执行和资源利用。进行这些操作时,需要保证相应的阻塞和唤醒语句成对出现,以确保进程状态转换的正确性。
4.进程的通信
- 管道(Pipes):是⼀种半双⼯的通信⽅式,数据只能单向流动,用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。
- 共享内存(Shared memory):使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式。
- 消息队列(Message Queuing):消息队列是消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载⽆格式字节流以及缓冲区⼤⼩受限等缺点。
- 套接字(Sockets):适⽤于不同机器间进程通信,在本地也可作为两个进程通信的⽅式。
- 信号(Signal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
- 信号量(Semaphores):信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。
5.线程
(1)线程的概念
线程(Thread)通常被称为轻量级进程,因为线程是在进程内部创建和管理的,相较于整个进程来说,线程具有更小的开销和更快的上下文切换速度。线程是一个基本的CPU执行单元,也是程序执行流的最小单位。多个线程可以在同一个进程内并发执行,并且它们共享该进程的资源,如内存空间、文件句柄、网络连接等。
举例来说,当你打开微信时,可能会有多个不同的线程在后台同时执行不同的任务。例如,存在一个专门负责拉取别人给你发送的最新消息的线程,该线程定期检查服务器是否有新消息,并将其显示在你的微信聊天界面上。同时,还可能有其他线程负责处理用户的输入、更新UI界面等任务。
引入线程之后,不仅是进程之间可以并发,进程内的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种任务(如QQ视频、文字聊天、传文件)
(2)进程与线程的区别
进程和线程是操作系统中用于实现并发执行的基本单位,它们之间有以下几点区别:
-
定义:进程(Process)是程序的一次执行过程,是资源分配的基本单位;线程(Thread)是进程中的一个执行单元,是CPU调度的基本单位。
-
资源占用:进程拥有独立的地址空间和系统资源(如文件句柄、内存空间),而线程共享相同进程的资源,包括内存空间、文件句柄等。
-
切换开销:进程之间的切换开销比线程大,因为进程间切换需要切换地址空间和系统资源;线程切换开销较小,因为线程共享相同进程的资源。
-
通信:进程间通信需要额外的机制(如共享内存、消息传递),而线程可以直接通过共享内存来进行通信。
-
独立性:进程是独立的执行实体,一个进程崩溃不会影响其他进程;线程是进程内的一个执行单元,一个线程崩溃可能导致整个进程崩溃。
-
创建销毁:创建和销毁进程的开销比创建和销毁线程的开销大,因为进程需要分配独立的系统资源;线程的创建和销毁开销小。
总的来说,进程是资源分配的基本单位,而线程是CPU调度的基本单位。在实际编程中,线程通常用于提高程序的并发性能,而进程通常用于实现系统间的通信和解耦。选择使用进程还是线程取决于具体的应用场景和需求。
二、进程调度
1. 操作系统调度机制
(1)调度的概念
进程都期望能够占用CPU进行工作,当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规则来决定处理,这些任务的顺序,这就是“调度”研究的问题。
这种选择进程并让其运行的功能是由操作系统中的调度程序(scheduler)完成的。调度程序负责根据一定的调度算法,决定在给定时刻哪个进程应该优先获得CPU的使用权,从而实现对系统资源的合理调度和分配。
通过调度程序的工作,操作系统能够有效地管理系统中多个进程的执行顺序和时间片分配,以确保系统资源的高效利用和任务的及时完成。不同的调度算法可能导致不同的进程调度方式,如先来先服务、最短作业优先、轮转调度等。
进程切换是有代价的,因此如果过于频繁的进行进程调度、切换,必然会使整个系统的效率降低,
使系统大部分时间都花在了进程切换上,而真正用于执行进程的时间减少。
(2)调度的三个层次
- 高级调度(作业调度):按一定的原则从外存的作业后备队列中挑选一个作业调入内存,并创建进程。每个作业只调入一次,调出一次。作业调入时会建立PCB,调出时才撤销PCB。
- 中级调度(内存调度):按照某种策略决定将哪个处于挂起状态的进程重新调入内存。一个进程可能会被多次调出、调入内存,因此中级调度发生的频率要比高级调度更高。
- 低级调度(进程调度/处理机调度):按照某种策略从就绪队列中选取一个进程,将处理机分配
给它。
调度方法 | 调度发生位置 | 发生频率 | 进程状态 | |
---|---|---|---|---|
高级调度(作业调度) | 按照某种规则,从后备队列中选择合适的作业将其调入内存,并为其创建进程 | 外存->内存(面向作业) | 最低 | 无->创建态->就绪态 |
中级调度(内存调度) | 按照某种规则,从挂起队列中选择合适的进程将其数据调回内存 | 外存->内存(面向进程) | 中等 | 挂起态->就绪态(阻塞挂起->阻塞态) |
低级调度(进程调度) | 按照某种规则,从就绪队列中选择一个进程为其分配处理机 | 内存->CPU | 最高 | 就绪态->运行态 |
(3)调度时机
在进程的生命周期中,每当进程从一种运行状态转变到另一种状态时,都会触发一次操作系统的调度机制。具体而言,以下几种状态变化均会激活操作系统的调度流程:
- 当进程被初始化并加入到就绪队列时,它会从就绪态转变为运行态。此时,操作系统会从就绪队列中精心挑选一个进程来占用CPU执行;
- 若进程在执行过程中遇到I/O事件而陷入阻塞态,即从运行态转变为阻塞态,操作系统便会迅速做出响应,从就绪队列中选取另一个进程来接替CPU的执行权;
- 当进程执行完毕并转入结束态,即从运行态转变为结束态时,操作系统同样需要采取行动,从就绪队列中挑选新的进程来继续利用CPU资源。
在这些状态转换的关键时刻,操作系统必须审慎地决定是否要让新的进程接管CPU,或者是否要让当前进程腾出CPU资源以供其他进程使用。
(4)调度的方式
-
非剥夺调度方式,又称为非抢占方式,指的是只允许进程主动放弃处理器。即使有更紧急的任务到达,当前进程仍将继续使用处理器,直到该进程终止或主动要求进入阻塞状态。这种方式实现简单,系统开销小,但无法及时处理紧急任务,适合于早期的批处理系统。
-
剥夺调度方式,又称为抢占方式,指的是当一个进程正在处理器上执行时,如果有一个更重要或更紧急的进程需要使用处理器,系统会立即暂停当前执行的进程,并将处理器分配给更重要或更紧急的进程。这种方式可以优先处理紧急进程,也可以通过时间片轮转实现让各个进程轮流执行(通过时钟中断)。适合于分时操作系统和实时操作系统。
这两种调度方式在处理任务优先级和响应速度方面有所不同,选择合适的调度方式取决于系统的需求和设计目标。非剥夺调度方式简单高效,适用于一些不需要立即响应的场景;而剥夺调度方式则更适合于需要优先处理紧急任务或实时任务的情况。
2. 调度算法的原则
调度算法的调度原则与其对应的评价指标如下:
- CPU利用率
- 基本概念:指CPU "忙碌"的时间占总时间的比例。
- 调度原则:在早期由于CPU造价昂贵,人们希望让CPU尽可能多地工作。
- 计算方法:
C P U 利用率 = 忙碌时间 总时间 CPU利用率 = \frac{忙碌时间}{总时间} CPU利用率=总时间忙碌时间
- 系统吞吐量:
- 基本概念:单位时间内完成作业的数量。
- 调度原则:计算机希望在尽可能短的时间内处理尽可能多的作业。
- 计算方法:
系统吞吐量 = 完成作业数量 总时间 系统吞吐量 = \frac{完成作业数量}{总时间} 系统吞吐量=总时间完成作业数量
- 周转时间:
- 基本概念:作业被提交给系统开始,到作业完成为止所经历的时间间隔,包括作业调度、进程调度、CPU执行和I/O等待时间。
- 调度原则:从对用户来说,关心作业从提交到完成所需的时间。
- 计算方法:
作业周转时间 = 作业完成时间 − 作业提交时间 作业周转时间 = 作业完成时间 - 作业提交时间 作业周转时间=作业完成时间−作业提交时间
平均周转时间 = 所有作业周转时间之和 作业数 平均周转时间 = \frac{所有作业周转时间之和}{作业数} 平均周转时间=作业数所有作业周转时间之和
带权周转时间 = 作业周转时间 作业实际运行的时间 = 作业完成时间–作业提交时间 作业实际运行的时间 带权周转时间 = \frac{作业周转时间}{作业实际运行的时间}=\frac{作业完成时间 – 作业提交时间}{作业实际运行的时间} 带权周转时间=作业实际运行的时间作业周转时间=作业实际运行的时间作业完成时间–作业提交时间
平均带权周转时间 = 各作业带权周转时间之和 作业数 平均带权周转时间 = \frac{各作业带权周转时间之和}{作业数} 平均带权周转时间=作业数各作业带权周转时间之和
-
等待时间
- 基本概念:进程或作业在等待处理机状态的时间总和,等待时间越长,用户满意度越低。
- 调度原则:用户希望作业尽可能减少等待时间,不包括等待I/O完成时间。
- 计算方法:对进程来说,等待时间是进程建立后等待服务的时间,不包括等待I/O完成时间;对作业来说,包括外存后备队列中等待时间。
-
响应时间
- 基本概念:从用户提交请求到系统产生首次响应所需的时间。
- 调度原则:用户希望用户请求(如键盘输入调试命令)尽快得到系统服务和响应。
这些指标对于评估计算机系统性能和用户体验至关重要。通过监控和优化这些指标,可以提高系统效率和用户满意度。
3. 调度算法
- 先来先服务调度算法(First Come First Severd, FCFS)
- 算法思想:主要从“公平”的角度考虑。
- 算法规则:先来后到,按照作业/进程到达的先后顺序进行服务。
- 抢占性:是非抢占式的算法。
- 最短作业优先调度算法(Shortest Job First, SJF)
- 算法思想:追求最少的平均等待时间,最少的平均周转时间、最少的平均平均带权周转时间。
- 算法规则:它会优先选择最短的作业/进程运行。
- 抢占性:是非抢占式的算法。
- 高响应比优先调度算法(Highest Response Ratio Next, HRRN)
- 算法思想:要综合考虑作业/进程的等待时间和要求服务的时间。
- 算法规则:在每次调度时先先计算**“响应比”**,然后把“响应比”最高的进程投入运行。
- 抢占性:是非抢占式的算法。
响应比 = 等待时间 + 要求服务时间 要求服务时间 响应比 = \frac{等待时间+要求服务时间}{要求服务时间} 响应比=要求服务时间等待时间+要求服务时间
- 时间片轮转调度算法(Round Robin, RR)
- 算法思想:公平地、轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应
- 算法规则:每个进程被分配一个时间段,称为时间片(Quantum),即允许该进程在该时间段中运行
- 抢占性:是抢占式的算法。
- 最高优先级调度算法(Highest Priority First,HPF)
- 算法思想:调度是有优先级的,即希望调度程序能从就绪队列中选择最高优先级的进程进行运行
- 算法规则: 每个作业/进程有各自的优先级,调度时选择优先级最高的作业/进程
- 抢占性:抢占式和非抢占式都有的算法。
- 多级反馈队列调度算法(Multilevel Feedback Queue)
- 算法思想:“时间片轮转算法”和“最高优先级算法”的折中权衡,
- 算法规则:设置多级就绪队列,各级队列优先级从高到低,时间片从小到大;新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片,若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经是在最下级的队列,则重新放回该队列队尾;只有第 k 级队列为空时,才会为 k+1 级队头的进程分配时间片
- 抢占性:是抢占式的算法。
三、进程的同步与互斥
进程具有异步性的特征。异步性是指,各并发执行的进程以各自独立的、不可预知的速度向前推进。
1. 进程的同步与互斥
在操作系统中,一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行,为了实现多个程序同时运行的假象,操作系统通常以时间片调度的方式,间片用完了,就切换下一个进程运行,由于这个时间片的时间很短,这就是 并发(Concurrent ) 现象。
(1)同步(Synchronization)
在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。
例如,让系统计算1+2x3,假设系统产生两个进程:一个是加法进程,一个是乘法进程。要让计算结果是正确的,一定要让加法进程发生在乘法进程之后,但实际上操作系统具有异步性若不加以制约,加法进程发生在乘法进程之前是绝对有可能的,因此要制定一定的机制去约束加法进程,让它在乘法进程完成之后才发生。
为了协调进程之间的相互制约关系,引入了进程同步的概念。同步(Synchronization) 亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作。
简单来说就是:所谓同步,就是并发进程/线程在一些关键点上可能需要互相等待与互通消息。
(2)互斥(Mutualexclusion)
进程的“并发”需要“共享”的支持。各个并发执行的进程不可避免的需要共享一些系统资源(比如内存,又比如打印机、摄像头这样的I/O设备)。
我们把一个时间段内只允许一个进程使用的资源称为临界资源(Critical Resources)。它是访问共享资源的代码片段,一定不能给多进程同时执行。每个进程中访问临界资源的那段代码称为临界区(Critical Section)。
对临界资源的访问,必须互斥地进行。互斥(Mutualexclusion),亦称间接制约关系。进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。
简单来说就是说:保证一个进程在临界资源执行时,其他进程应该被阻止访问临界资源(阻止进入临界区)。
(3)同步与互斥对比
- 同步:进程 A 应在进程 B 之前执行,进程C 必须在进程 A 和进程 B 都完成之后才能执行等;
- 互斥:进程A 和进程 B不能在同一时刻执行。
2. 锁
使用加锁操作和解锁操作可以解决并发线程/进程的互斥问题。
任何想进入临界区的线程,必须先执行加锁操作。若加锁操作顺利通过,则线程可进入临界区;在完成对临界资源的访问后再执行解锁操作,以释放该临界资源。
3. 信号量
1965年,荷兰学者Dijkstra提出了一种卓有成效的实现进程互斥、同步的方法,即 信号量机制。
信号量是操作系统提供的一种协调共享资源访问的方法。信号量其实就是一个变量(sem) ,可以用一个信号量来表示系统中某种资源的数量。
有两个原语的系统调用函数来控制信号量的,分别是wait(S) 原语和 signal(S) 原语。wait、signal 原语常简称为 P、V操作(来自荷兰语 proberen 和 verhogen)。因此,做题的时候常把wait(S)、signal(S) 两个操作分别写为 P(S)、V(S)。
- P 操作:将 sem 减 1,相减后,如果 sem < 0,则进程/线程进入阻塞等待,否则继续,表明 P 操作可能会阻塞;
- V 操作:将 sem 加 1,相加后,如果 sem <= 0,唤醒一个等待中的进程/线程,表明 V 操作不会阻塞。
例如:
如果 sem = 1,有三个线程进行了 P 操作:
第一个线程 P 操作后,sem = 0;
第二个线程 P 操作后,sem = -1;
第三个线程 P 操作后,sem = -2;
这时,第一个线程执行 V 操作后, sem 是 -1,因为 sem <= 0,所以要唤醒第二或第三个线程。
四、死锁
1. 死锁的概念
在多线程编程中,我们为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。 那么,当两个线程为了保护两个不同的共享资源而使用了两个互斥锁,那么这两个互斥锁应用不当的时候,可能会造成两个线程都在等待对方释放锁,在没有外力的作用下,这些线程会一直相互等待,就没办法继续运行,这种情况就是发生了死锁。
死锁、饥饿、死循环的区别:
- 死锁:各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进的现象。
- 饥饿:由于长期得不到想要的资源,某进程无法向前推进的现象。比如:在短进程优先(SPF)算法
中,若有源源不断的短进程到来,则长进程将一直得不到处理机,从而发生长进程“饥饿” - 死循环:某进程执行过程中一直跳不出某个循环的现象。有时是因为程序逻辑bug导致的,有时是
程序员故意设计的。
2. 死锁产生的必要条件
产生死锁必须同时满足一下四个条件,只要其中任一条件不成立,死锁就不会发生。
- 互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待这种资源)。
- 不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
- 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
- 循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求
注意!发生死锁时一定有循环等待,但是发生循环等待时未必死锁
3. 死锁的处理策略
(1)破坏互斥条件
互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁。
如果把只能互斥使用的资源改造为允许共享使用,则系统不会进入死锁状态。比如: SPOOLing技术。操作系统可以采用 SPOOLing 技术把独占设备在逻辑上改造成共享设备。比如,用SPOOLing技术将打印机改造为共享设备…
(2)破坏不剥夺条件
不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
破坏不剥夺条件:
方案一:当某个进程请求新的资源得不到满足时,它必须立即释放保持的所有资源,待以后需要时再重新申请。也就是说,即使某些资源尚未使用完,也需要主动释放,从而破坏了不可剥夺条件。
方案二:当某个进程需要的资源被其他进程所占有的时候,可以由操作系统协助,将想要的资源强行剥夺。这种方式一般需要考虑各进程的优先级(比如:剥夺调度方式,就是将处理机资源强行剥夺给优先级更高的进程使用)