[ 操作系统 ] 第二章 —— 进程管理

进程管理

进程与线程

概念

定义:进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。

组成:

  1. PCB:进程存在的唯一标志。PID不同。
  2. 程序段:存放程序代码。
  3. 数据段:存放程序运行中的数据。

组织形式:

  1. 链接方式:按照进程状态将PCB分为多个队列,链表连接方式。
  2. 索引方式:按照进程状态建立不同的索引表,表项指向PCB。

特征:

  1. 动态性:最基本的特征。
  2. 独立性:进程是系统进行资源分配、调度的独立单位。
  3. 异步性、并发性、结构性。

进程状态

三种状态:运行状态、就绪状态、阻塞状态。

状态转换:

  1. 不存在由(阻塞态——>运行态)和(就绪态——>阻塞态)的转换。
  2. (运行态——>阻塞态)是主动的过程,(阻塞态——>就绪态)是被动的过程。

进程控制

概念:

  1. 通过进程控制来实现进程状态转换。
  2. 原语需要一气呵成,不可中断。关中断、开中断。

相关原语:创建、终止、阻塞、唤醒、切换。

进程通信

共享存储:设置一个共享空间,但需要保证进程的互斥访问。

  1. 基于数据结构的共享:只能存储某种数据结构的数据。
  2. 基于存储区的共享:高级共享。

管道通信:设置一个管道,即缓冲区,进行读写操作。

  1. 进行半双工通信(单向),互斥访问。
  2. 写满时,不能再写。读空时,不能再读。
  3. 没写满,不能读。没读空,不能写。

消息传递:结构化消息,含消息头(发送方、接收方等进程信息)、消息体。

  1. 直接通信方式:消息挂到接收方的消息队列中。
  2. 间接通信方式:发到信箱。
  3. 使用发送/接收原语。

线程

线程属性:

  1. 线程成为CPU分配的基本单位,进程是资源分配的单位。
  2. 同一进程的不同线程共享资源,共享内存地址空间,不需要系统干预。
  3. 同一进程内的线程切换不会引起进程的切换。
  4. 也有就绪、阻塞等状态。

实现方式:

  1. 用户级线程 ;多对一模型:一个线程阻塞,会导致整个进程都被阻塞。
  2. 内核级线程 ;一对一模型:一个用户级线程对应一个内核级线程

本节错题

  1. 优先级可以分为静态和动态两种,动态优先级可根据运行情况随时调整,而不是不可改动的。

  2. 系统发生死锁时,有可能进程全都处于阻塞态,或无进程任务。因此,并非任何时刻都有进程处于运行态。

  3. 程序是静态的,进程是动态的。不可将两者相互描述。

  4. 新进程进入就绪态,不会导致运行态转变为其他状态。

  5. 进程的就绪数目越多,争夺CPU的进程就越多,但只要就绪队列不为空,CPU就总是可以调度进程运行,保持繁忙。这与就绪进程的数目没有关系,除非就绪队列为空,此时CPU进入等待态,导致CPU的效率下降。

  6. 由于引入线程后,线程变为处理机调度的基本单位,因此,同一进程或不同进程的线程都可以并发执行。

  7. 降低进程优先级的时机:进程的时间片用完。提高优先级的时机:进程完成IO操作进入就绪队列、长期处于就绪状态。

  8. 进程被唤醒,进入就绪状态,而不是运行态。优先级可能被适当提高。

  9. 进程可以创建进程或线程,线程也可以创建线程,但线程不能创建进程。

处理机调度

概念

调度:从就绪队列中按照一定的算法选择一个进程,并将CPU分配给他。

三种调度:

  1. 高级调度(作业调度):选择合适的作业调入内存。(外存 ==》内存,面向作业)
  2. 中级调度(内存调度):从挂起的队列中选择合适的进程调入内存。(外存 ==〉内存,面向进程)
  3. 低级调度:为进程分配处理机。

进程调度

进程调度的主动与被动:

  1. 主动放弃:进程正常终止、运行过程中发生异常而终止、主动阻塞。
  2. 被动放弃:时间片用尽、优先级更高的进程、更紧急的进程。

不能进行进程调度:进程在操作系统内核程序临界区;处理中断;原语过程。

评价指标

系统吞吐量:单位时间内完成作业的数量。
\[ 系统吞吐量 = \frac{总共完成了多少道作业}{总共花了多少时间} \]
周转时间:从作业被提交给系统,到最后完成为止的时间间隔。

带权周转时间:值越小,满意度越高。必然>=1。
\[ 周转时间 = 作业完成时间 - 作业提交时间 \\ 平均周转时间 = \frac{各作业周转时间之和}{作业数}\\ 带权周转时间 = \frac{作业周转时间}{作业实际运行时间}\\ 平均带权周转时间 = \frac{各作业带权周转时间和}{作业数} \]

调度算法

先来先服务FCFS:按照到达的先后顺序调度,事实上就是等待时间越久的越优先得到服务。

优点:公平、算法实现简单。非抢占式。

缺点:对长作业有理,对短作业不利。

短作业优先SJF:最短的作业或进程得到服务。如果运行时间相同,则选择先到达的进程运行。

最短剩余时间优先:比较新进程和正在运行的进程的剩余时间。(抢占式)

缺点:对短作业有利,长作业不利。会导致饥饿现象,源源不断的短作业等,则长作业长时间得不到服务。

高响应比优先HRRN:不会导致饥饿。
\[ 响应比 = \frac{等待时间+要求服务时间}{要求服务时间} \]

时间片轮转RR

  1. 轮流让各个进程执行一个时间片,若在一个时间片内未执行完成,则剥夺处理机。
  2. 用于进程调度。(只有作业放入内存建立了相应的进程后,才能被分配处理机时间片)
  3. 抢占式算法;时钟中断宣布时间片到。
  4. 在运行过程中,如果同一时刻,既有进程下处理机,又有新进程到达,则默认新到达的进程先进入就绪队列。
  5. 如果时间片太大,时间片轮转调度算法退化为先来先服务调度算法,会增大进程相应时间。时间片太小,又会导致进程切换过于频繁。
  6. 不会导致饥饿。

优先级调度算法

  1. 每个作业、进程都有各自的优先级,调度时选择优先级高的。
  2. 如果进程在就绪队列等了太长时间,可以适当提高其优先级。如果一个进程频繁进行IO操作,可以适当提高。
  3. 优点:用优先级区分紧急程度,适用于实时操作系统。可灵活地调整对各个作业的偏好程度。
  4. 会导致饥饿。

多级反馈队列调度算法

  1. 用于进程调度;抢占式算法。
  2. 设置多级就绪队列,各级队列优先级从高到低,时间片从小到大。
  3. 若用完时间片,进程还未结束,则进程进入下一级队列队尾。
  4. 只有第k级队列为空时,才会为k+1级队头的进程分配时间片。
  5. 被抢占处理机的进程重新放回原队列队尾。
  6. 会导致饥饿。源源不断短进程到达,被降级的优先级会长期得不到服务。

进程同步与互斥

概念

进程同步:进程的直接制约关系,各个进程的工作推进需要遵循一定的先后顺序

进程互斥:对临界资源的访问,需要互斥的进行。即同一时间段内只能允许一个进程访问该资源。

  1. 进入区检查并上锁。退出去解锁。
  2. 临界区访问临界资源的代码。剩余区时其余代码部分。
  3. 遵循原则:空闲让进、忙则等待、有限等待、让权等待(while循环等待)。

进程互斥的软件实现方法

单标志法

  1. 两个进程在访问完临界区后会把使用临界区的权限交给另一个进程。
  2. 根据例子可知,尽管临界区是空闲的,也有可能出现不允许另一进程访问的情况。
  3. 违背了空闲让进的原则。

双标志先检查法

  1. 设置一个bool数组,数组中各个元素用来标记各进程是否想要进入临界区。flag[0]=true意味着0号进程现在想要进入临界区。
  2. 由于异步性,可能会导致进程同时访问临界区。违背了忙则等待原则。
  3. 原因在于:进入区的检查和上锁的处理不是一气呵成的。

双标志后检查法

  1. 由于异步性,可能导致进程都无法进入临界区。
  2. 解决了忙则等待原则,但是又违背了空闲让进和有限等待的问题。会产生饥饿现象。

Peterson算法

  1. 进入区:主动争取、主动谦让,检查对方是否谦让。
  2. 不遵循让权等待原则,会发生忙等。

进程互斥的硬件实现方法

中断屏蔽:“开/关中断指令”的实现。

缺点:

  1. 不适合多处理机。比如现有某一进程正在访问临界区,而另一进程正在运行且需要访问同一临界区,就会导致冲突。
  2. 只适用于内核进程,不适用于用户进程。因为两指令权限很大。

TestAndSet

  1. TSL指令是用硬件实现的,执行过程不允许被中断,只能一气呵成。
  2. 缺点:不满足让权等待原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从而导致忙等。
  3. 记录以前的lock值,修改lock值。

swap指令:逻辑上和TSL相同。

信号量机制

整型信号量:该整数表示某一资源的可用数量。

记录型信号量semaphore:

  1. P操作:该进程请求一个单位的资源,先执行value--,若结果<0,说明该资源之前已经分配完毕,因此该进程需要调用block原语进行自我阻塞,即从当前运行的进程从(运行态 --> 阻塞态),主动放弃处理机,并插入该类资源的等待队列中。
  2. V操作:释放一个单位的资源,先执行value++,若结果<=0,说明此时仍然有进程在等待该类资源,应调用wakeup原语唤醒等待该资源的进程。(阻塞态 --> 就绪态)

信号量实现互斥、同步

互斥实现步骤

  1. 分析并发进程的关键活动,划定临界区。(比如说打印机是需要互斥访问,这类资源就应该放在临界区)
  2. 设置互斥信号量mutex,初值为1。(信号量的名字可以任意设置。而具体的值,则是根据资源数量而设置)
  3. 在临界区之前执行P(mutex)
  4. 在临界区之后执行V(mutex)

注意

  1. 对不同的临界资源,需要设置不同的互斥信号量。
  2. P、V操作需要成对出现。缺少P导致不能保证资源的互斥访问。缺少V导致资源不被释放,进程不被唤醒。

同步实现步骤(需要一前一后执行的操作):

  1. 分析什么地方需要实现同步关系。
  2. 在“前操作”之后执行V(S)
  3. 在“后操作”之前执行P(S)

注意

  1. 执行完P、V操作后,S的结果还是0。
  2. 如果先执行P操作,会主动阻塞。然后在V操作中执行wakeup原语唤醒该阻塞进程。
  3. 如果先执行V操作,执行P操作时就知道,此时有可用资源。

实现前驱关系:

  1. 要为每一对前驱关系各设置一个同步变量。 S1 ---> S2; S1 ---> S3....
  2. 根据自身情况,执行相应的P、V操作。

生产者-消费者问题

生产者消费者问题是一个互斥、同步的综合问题。

解题要点

  1. 两对同步关系:有时候是消费者需要等待生产者生产、有时候是生产者要等待消费者消费。因此是两个同步信号量。

    如图所示,实际上,full 和 empty的名字不是我们的关注点。问题在于,根据箭头方向,决定两者的前后顺序。

  2. 一对互斥关系:对于临界区的访问,通常是为 1 的。

  3. 注意实现互斥和同步的两个P操作的先后顺序。如果任意的交换位置,可能会导致死锁现象,即相互等待。

多生产者-多消费者问题

  1. 不设置专门的mutex,也不会出现多个进程同时访问盘子的现象的原因:

答:当缓冲区的大小为1时,在任何时刻,多类同步信号量中最多只有一个是1,所以最多只有一个进程的P操作不会被阻塞,并且顺利地进入临界区。

  1. 如果把盘子(缓冲区)数量改成>=2:

    答:如果没有mutex,可能会导致缓冲区数据覆盖的情况,即两个进程同时访问同一块缓冲区。

  2. 要把对“行为动作”的分析转变成对事件的分析。 盘子变空 ===》放入水果。(不是很明白)

吸烟者问题

假设一个系统有三个抽烟者进程和一个供应者进程。

同步关系:四个同步关系。

互斥关系:桌子可以抽象为容量为1的缓冲区。且有三种组合。

这里我有点疑问。为什么producer的P操作不是放在if语句之前。
image-20200228221228252

读者-写者问题

问题描述:

  1. 允许多个读者同时对文件执行读操作。
  2. 只允许一个写者往文件中写信息。
  3. 任一写者在完成写操作之前不允许其他读者或写者工作。
  4. 写者执行写操作前,应让已有的读者和写者全部退出。

主要思想:

  1. 其核心思想在于设置了一个计数器count用来记录当前正在访问共享文件的读进程数。我们可以用count的值来判断当前进入的进程是否是第一个(进行加锁)/最后一个(进行解锁)进程。
  2. 又由于count变量的检查和赋值不能一气呵成,从而导致某些错误,因此要借助互斥信号量。

哲学家问题

问题描述:

  1. 哲学家进餐问题的关键在于解决进程死锁:进程之间只存在互斥关系,而此时每个进程都需要同时持有两个临界资源,因此就有死锁的可能。
  2. 对于解决方案:各哲学家拿筷子这件事必须互斥的进行。这就保证了即使一个哲学家在拿筷子拿到一半时被阻塞,也不会有别的哲学家会继续尝试拿筷子。这样的话,当前正在吃饭的哲学家放下筷子后,被阻塞的哲学家就可以获得等待的筷子了。

管程

管程的引入:解决信号量机制编程麻烦的问题,更好地实现同步互斥。

基本特征:

  1. 管程中需要定义共享数据结构,对其初始化,再定义一组用来访问该结构的函数。
  2. 各外部进程/线程只能通过管程提供的特定入口才能访问共享数据。
  3. 每次仅允许一个进程在管程内执行某个内部过程。

补充:

  1. 这种互斥特性是由编译器负责实现的。
  2. 可在管程中设置条件变量及等待/唤醒操作以解决同步问题。

死锁

概念

死锁、饥饿、死循环

共同点:都是进程无法顺利向前推进

不同点:

  1. 死锁是“循环等待对方手里的资源”导致。因此必须要有两个或两个以上的进程同时发生死锁。发生死锁的进程一定处于阻塞态。
  2. 饥饿可能只有一个进程发生饥饿。发生饥饿的进程即可能是阻塞态(等待io设备),也可能是就绪态(长期得不到处理机)。
  3. 死循环是被管理者的问题,是可以上处理机上运行的。死锁和饥饿是管理者进行调度方案不佳的问题,处于核心态。

死锁产生的必要条件

  1. 互斥条件:对必须互斥使用的资源争抢。
  2. 不剥夺条件:只能是进程主动释放资源,不可剥夺。
  3. 请求和保持条件:保持某种资源不放的同时,请求别的资源。
  4. 循环等待条件:存在一种进程资源的循环等待链条。循环等待未必死锁。

处理死锁的策略

  1. 预防死锁:破坏产生条件。
  2. 避免死锁:避免系统进入不安全状态。
  3. 死锁的检测和解除:允许死锁发生,系统负责检测出死锁并解除。

预防死锁

四种方法与各自缺点

破坏互斥条件 方法 缺点
破坏不剥夺条件 申请资源得不到满足时,立即释放拥有的所有资源;申请的资源被其他进程占用时,由操作系统协助剥夺。 可行性不高。
破坏请求和保持条件 运行前分配好所有需要的资源,之后一直保持。 剥夺资源可能导致部分工作实效;反复申请和释放导致系统开销大;导致饥饿。
破坏循环等待条件 给资源编号,必须按编号从小到大的顺序申请资源。 资源利用率低;可能导致饥饿。
破坏互斥条件 将临界资源改造为可共享使用的资源(SPOOLing技术)。 不方便增加新设备;会导致资源浪费。

避免死锁

银行家算法步骤:

  1. 检查此次申请是否超过了之前声明的最大需求数。
  2. 检查此时系统剩余的可用资源是否还能满足这次请求。
  3. 试探分配,修改数据结构
  4. 用安全性算法检查此次分配是否会导致系统进入不确定状态。

安全性算法步骤:

  1. 检查当前的剩余可用资源是否能满足某个进程的最大需求,如果可以,则将他加入安全序列,并把该进程持有的资源全部回收。
  2. 不断重复上述过程,看最终是否能让所有进程都加入安全序列。

系统处于不安全状态未必死锁,但死锁一定处于不安全状态。

死锁的检测和解除

死锁检测算法:

  1. 依次消除与不阻塞进程相连的边,直到无边可消,求出安全序列。
  2. 若资源分配图时不可完全简化的,说明发生了死锁。

死锁的解除:

  1. 资源剥夺法:挂起死锁进程,并抢占它的资源。
  2. 撤销进程法:强制撤销部分或全部进程。又可能导致功亏一篑。
  3. 进程回退法:让一个或多个死锁进程回退到足以避免死锁的地步。这需要系统记录进程的历史信息,设置还原点。

猜你喜欢

转载自www.cnblogs.com/recoverableTi/p/12382554.html