onein

导航

第二章:2.2进程调度-死锁-存储管理-固定分页分段

    • 当进程处于就绪状态时,需要CPU进行进程调度算法才可从就绪状态改变为运行(执行)状态。(进程调度算法只是从就绪状态到运行状态的决策,而实际的状态转换和执行由操作系统内核来完成。操作系统会根据调度算法的结果,将选择的进程加载到CPU并执行,完成进程的切换和调度)
    • 进程调度的方式,此处我们先了解优先级调度,即当有更高级的进程来时,根据优先级进行分配,同时当前运行的进程分为 可剥夺 与不可剥夺 的进程。
      • 先来先服务(First-Come, First-Served,FCFS):按照进程到达的顺序进行调度,即先到先服务的原则
      • 短作业优先(Shortest Job Next,SJN):选择估计运行时间最短的进程进行执行,以减少等待时间。
      • 优先级调度(Priority Scheduling):为每个进程分配一个优先级,根据优先级高低来选择下一个要执行的进程。
      • 时间片轮转(Round Robin,RR):将CPU时间划分为固定大小的时间片,每个进程轮流执行一个时间片,然后切换到下一个进程。
      • 多级反馈队列调度(Multilevel Feedback Queue Scheduling):将进程划分为多个优先级队列,按照不同的策略进行调度。设置多个就绪队列,每个队列设置不同的优先级,根据优先级分配不同的时间片长度,优先级越高,时间片越长,队列执行按照时间片流转进行执行。
    • 定义:所有进程进入阻塞状态,就会产生死锁。若系统有多个进程处于死锁状态,就会造成系统死锁。
    • 死锁产生的四大必要条件
      • 资源互斥:一个资源同时只能被一个进程占用,如果一个进程占用了资源A,其他进程就无法访问资源A。
      • 每个进程占有资源并且等待其他资源:一个进程在持有部分资源的同时,又请求其他进程所占有的资源。
      • 系统不能剥夺进程资源:已经分配给一个进程的资源不能被强制性地抢占,只能由持有该资源的进程显式释放。
      • 进程资源是个环路:多个进程之间形成一个循环等待资源的链,例如进程A等待进程B的资源,进程B等待进程C的资源,进程C等待进程A的资源。
    • 解决措施,打破四大条件
      • 死锁预防
        • 破坏互斥条件:例如,对于可重入资源,允许多个进程同时访问。
        • 破坏请求与保持条件:进程在申请资源时一次性申请所需的全部资源,而不是逐个申请。
        • 破坏不剥夺条件:允许操作系统抢占进程的资源,以满足其他进程的需求。
        • 破坏循环等待条件:对所有资源进行线性排序,并要求进程按照相同的顺序请求资源,从而避免形成循环等待。
      • 死锁避免
        • 利用资源分配图(Resource Allocation Graph)来避免产生环路,从而避免死锁的发生。
        • 使用银行家算法(Banker's Algorithm)来预判资源分配是否会导致死锁,并根据判断结果进行资源的合理分配。
      • 死锁检测与解除
        • 运行时通过资源分配图或其他算法检测死锁的发生。
        • 一旦检测到死锁,可以采取以下策略进行解除:
          • 进程终止:终止部分或全部进程来释放资源。
          • 资源抢占:抢占一部分或全部资源,将其分配给其他进程。
          • 进程回退:回滚进程到之前的状态,释放所持有的资源
      • 死锁资源计算
        • 死锁最大资源数:进程个数n*(每个进程需要的资源R-1)
        • 不发生死锁的最小资源数:n*(R-1)+1
    • 传统的进程由:可拥有资源的独立单元;可以独立调度和分配的基本单元。
      • 组成:进程由程序控制块(PCB)和程序以及数据组成
      • 为什么要引入线程?
        • 传统的进程之间切换的开销较大,需要保存和恢复进程的上下文信息。为了克服这个问题,引入了线程的概念,线程是进程内的执行单元,可以与其他线程共享进程的资源,切换开销更小,提高了并发性能。
        • 提高系统的响应能力:通过引入线程,可以实现并发执行,即多个任务或操作可以同时进行。这样可以提高系统对用户请求的响应速度,提升用户体验。
        • 资源共享和效率:线程可以在同一个进程内共享资源,如内存、文件等。相比于创建多个独立进程,线程的切换开销更小,资源共享更高效,减少了资源的重复分配和管理开销。
        • 简化编程模型:在传统的进程模型中,不同进程之间通信和数据共享相对复杂,需要使用进程间通信(IPC)机制,如管道、共享内存等。而线程位于同一个进程内,共享相同的上下文,数据共享和通信更加简单和高效,减少了开发复杂性。
        • 节省系统资源:相比于创建多个独立进程,创建线程所需的系统资源开销更小。因为线程共享了进程的地址空间和其他资源,不需要单独为每个线程分配内存空间。
        • 适应多核处理器:随着多核处理器的普及,系统能够同时运行多个线程,并发地利用多个处理器核心,提高系统的整体性能。
      • 为了减少进程切换的开销并提高并发性能,引入了线程的概念。线程是进程内的执行单元,多个线程可以共享进程的资源和上下文信息。线程切换相较于进程切换的开销要小得多,因为线程之间共享了大部分的资源,只需切换少量的线程上下文信息。这样能够提高CPU的利用率和系统的并发性能。
      • 线程作为进程中的最基本执行单位有以下几个好处:
        • 更高的并发性:多线程编程可以充分利用系统的多核处理器和多任务调度功能,提高程序的并发性能。通过将任务拆分为多个线程并行执行,可以更有效地利用CPU资源,提高整体的执行速度。
        • 更低的开销:线程的创建、切换和销毁的开销相对较小,因为线程共享进程的资源和上下文信息。相比于创建和管理多个独立的进程,使用线程可以减少资源的消耗和系统开销。
        • 更容易的数据共享和通信:由于线程共享同一个进程的地址空间,它们之间可以直接访问和共享进程的数据,而无需进行额外的通信和数据传输。这使得线程之间的数据共享更加方便和高效。
      • 在大多数情况下,可以将任务拆分为多个线程来并行执行。但是需要注意以下几个方面:
        • 同步和互斥:在多线程环境下,线程之间可能会访问和修改共享数据。为了保证数据的一致性和避免竞态条件,需要合理地使用同步机制(如锁、信号量)来协调线程之间的执行顺序和数据访问。
        • 资源管理:线程共享进程的资源,如内存、文件描述符等。因此,在进行多线程编程时,需要合理管理和分配这些资源,避免出现资源竞争和耗尽的情况。
        • 线程安全性:在多线程环境中,如果多个线程同时访问和修改同一个数据,可能会导致数据不一致或者出现意料之外的错误。因此,需要确保线程安全性,例如使用原子操作、互斥锁等机制来保护共享数据
  • 存储管理
    • 分区存储管理
      • 固定分区:在固定分区存储管理中,物理内存被划分为固定大小的分区。每个分区都有自己的起始地址和大小。这些分区通常预先定义,并且不会动态改变大小。
      • 分区表:用于记录每个分区的状态(已分配或空闲)、起始地址、大小等信息的数据结构。分区表通常存储在操作系统的内存管理模块中。
      • 空闲分区管理:操作系统需要维护一个空闲分区列表,以便有效地分配空闲内存给进程。当一个进程需要内存时,操作系统会搜索空闲分区列表,选择一个合适大小的空闲分区,并将其分配给进程。
      • 内部碎片:由于分区的大小是固定的,当一个进程所需的内存小于分区的大小时,会导致分配给进程的分区存在内部碎片。内部碎片是指分区中未被利用的部分内存,造成了浪费。
      • 外部碎片:分区存储管理中存在外部碎片问题。外部碎片是指已经分配给进程的分区和空闲分区之间的一些零散的小块内存,这些小块内存无法满足一个大内存请求,导致内存利用率降低。
      • 分区分配算法:操作系统需要实现适当的分区分配算法来选择合适的分区分配给进程。常见的算法包括首次适应算法、最佳适应算法和最坏适应算法等。这些算法根据分区大小和分区状态等因素进行选择。
    • 分页存储管理
      • 原理:如果内存空间不够,无法进行整存,因此采用分页或者分段存储。利用程序的局部性原理,一页一页放入主存。
        • 页大小:提前约定固定好,需要运行的程序,最后一页可能与固定大小不一样,产生内部碎片。
        • 优点:利用率高、碎片小、分配及管理简单
        • 缺点:会增加系统开销,可能会产生抖动现象。
        • 抖动(thrashing)是指系统频繁地进行页面置换,导致大量的磁盘访问和CPU时间被浪费在页面置换操作上,而无法有效地执行实际的任务。抖动的效果是系统性能急剧下降,因为大量的时间被耗费在页面置换操作上,而不是实际的计算任务上。
      • 逻辑页分为页号和页内地址。
        • 物理地址 ↔️逻辑地址
          • 逻辑地址(内存):页
          • 物理地址(外存):页框或者页帧
          • 总页数:每页大小/主存大小
          • 页号大小:把页号划分成2的幂指数,有多少个页,就说明页号有多少个位,例如 有 2个 页 幂指数就是 1 ,用1个2进制 可以表示 0 和 1 ,2个页
            当逻辑页的数量是16时,我们需要至少4位来表示16个不同的页号。这是因为2^4等于16,所以使用4位二进制数足以表示从0到15的16个不同的页号。
            具体来说,我们可以将0表示为0000,1表示为0001,依次类推,直到15表示为1111。每个二进制位可以有两种状态(0或1),而对于4位二进制数,总共有2^4 = 16种不同的组合,可以用来表示页号。
            所以,当逻辑页数量是16时,我们需要4位二进制数来表示这16个不同的页号。
          • 页内地址大小:根据页的大小 转换为 2的幂指数
          • 页表:存储逻辑地址和页号的对应关系
      • 页面置换算法
        • 最优算法(Optimal Page Replacement):最优算法是一种理想化的算法,它会选择未来最长时间内不会被访问到的页面进行置换。这种算法在理论上可以保证获得最低的缺页率,但实际上很难实现,因为需要对未来访问顺序进行预测。
        • 先进先出算法(First-In-First-Out, FIFO):先进先出算法是一种简单的页面置换算法。它通过维护一个页面队列,当需要进行页面置换时,选择最早调入内存的页面进行置换。这种算法易于实现,但可能导致"先来的页面"过早地被置换出去,造成较高的缺页率。
        • 最近最少使用(Least Recently Used, LRU):最近最少使用算法是根据页面的历史访问情况来进行页面置换的。具体来说,它会选择最长时间未被访问的页面进行置换。LRU算法相对较为复杂,通常需要维护一个访问时间队列或者使用特殊的数据结构(如LRU缓存)来记录页面的使用情况。
      • 快表(Translation Lookaside Buffer, TLB)
        • 小容量的相联存储器,存放当前访问最频繁的少数活动页面的页号。
        • 存储在Cache中,是一种高速缓存,用于加速虚拟地址到物理地址的转换过程。在使用虚拟内存的系统中,当CPU访问一个虚拟地址时,需要将虚拟地址转换为物理地址,这个过程需要进行页表查找并进行页面置换。
    • 分段存储管理
      • 将进程空间分为一个个段,每段有短号和段内地址。
      • 段:程序或数据被划分为逻辑上相互独立的段,每个段具有自己的起始地址和长度。不同的段可以有不同的长度,这使得程序和数据的大小可以动态适应。每个段都可以被单独加载到内存中。
      • 段表:用于记录每个段的起始地址和长度的数据结构,通常存储在内存中。通过段表,操作系统可以实现地址映射,将逻辑地址转换为物理地址。
      • 外部碎片:由于段的长度可以动态变化,可能会导致内存中出现外部碎片问题。外部碎片是指内存中存在一些不连续的小块空闲内存,但它们无法满足某个段的大小需求,从而导致内存利用率降低。
      • 内部碎片:由于段的长度可以动态变化,可能会导致内部碎片问题。内部碎片是指一个段所占用的内存空间中,有一部分空间未被完全利用,造成了浪费。
      • 动态加载和动态链接:分段存储管理为程序的动态加载和动态链接提供了便利。程序的不同段可以分别加载到内存中,当需要时进行动态链接,从而实现更加灵活的程序开发和执行过程。
  •  

posted on 2023-08-16 17:25  ゛王哪跑  阅读(39)  评论(0)    收藏  举报