进程概述: 程序:是静态的,就是个存放在磁盘里的 可执行文件,就是一系列的指令集合。 进程(Process):是动态的,是程序的一 次执行过程,同一个程序多次执行会对应 多个进程
进程状态: 进程正在被创建时,它的状态是“创建态”,在这个阶段操作系统会为进 程分配资源、初始化PCB 当进程创建完成后,便进入“就绪态”, 处于就绪态的进程已经具备运行条件, 但由于没有空闲CPU,就暂时不能运行 如果一个进程此时在CPU上运行,那么这个进程处于“运行态”。CPU会执行该进程对应的程序(执行指令序列) 在进程运行的过程中,可能会请求等待某个事件的发生(如等待 某种系统资源的分配,或者等待其他进程的响应)。 在这个事件发生之前,进程无法继续往下执行,此时操作系统会 让这个进程下CPU,并让它进入“阻塞态” 当CPU空闲时,又会选择另一个“就绪态”进程上CPU运行。 一个进程可以执行 exit 系统调用,请求操作系统终止该进程。 此时该进程会进入“终止态”,操作系统会让该进程下CPU, 并回收内存空间等资源,最后还要回收该进程的PCB。 当终止进程的工作完成之后,这个进程就彻底消失了。
进程转换: 进程组织:
进程控制: 进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现 进程状态转换等功能。 简化理解:反正进程控制就是要实现进程状态转换.
用“原语”实现进程控制,原语是一种特殊的程序, 它的执行具有原子性。 也就是说,这段程序的 运行必须一气呵成,不可中断。
原语的执行具有原子性,即执行过程只能一气呵成,期间不允许被中断。 可以用 “关中断指令”和“开中断指令”这两个特权指令实现原子性
进程通信: 进程通信就是指进程之间的信息交换。 进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。 为了保证安全,一个进程不能直接访问另 一个进程的地址空间。 但是进程之间的信息交换又是必须实现的。 为了保证进程间的安全通信,操作系统提 供了一些方法。
线程概述: 进程是资源分配的基本单位。 当切换进程时,需要保 存/恢复进程运行环境, 还需要切换内存地址空 间(更新快表、更新缓存)开销很大。 引入线程后,线程是CPU调度的基本单位。 进程依然是资源分配的基本单位。 从属于同一进程的各个线程共享进程的资源 进程间并发,开销很大线程间并发,开销更小 引入线程机制后,并发带来的系统开销降低,系统并发性提升 从属同一进程的各个线程共享进程拥有的资源。 线程也有运行态、就绪态、阻塞态 在多CPU环境下,各个线程 也可以分派到不同的CPU上并行地执行。 线程的实现方式: 用户级线程由应用程序通过线程库实现,所有的线程管理工作都由应用程序负责(包括线程切换) 用户级线程中,线程切换可以在用户态下即可完成,无需操作系统干预。 在用户看来,是有多个线程。 但是在操作系统内核看来,并意识不到线程的存在。 “用户级线程”就是“从用户视角看能看到 的线程”
内核级线程的管理工作由操作系统内核完成。 线程调度、切换等工作都由内核负责,因此内核级线程的切换必然需要在核心态下才能完成。 操作系统会为每个内核级线程建立相应的TCB(Thread Control Block,线程控制块), 通过TCB对线程进行管理。 “内核级线程”就 是“从操作系统内核视角看能看到的线程”
处理机调度: 当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规则来决定处理 这些任务的顺序,这就是“调度”研究的问题。 在多道程序系统中,进程的数量往往是多于处理机的个数的,这样不可能同时并行地处理各个进程。 处理机调度就是从就绪队列中按照一定的算法选择一个进程并将处理机分配给它运行,以实现进程的并发执行
高级调度: 由于内存空间有限,有时无法将用户提交的作业全部放入内存,因此就需要确定某种规则来决定将作业调入内存的顺序。 高级调度(作业调度)。按一定的原则从外存上处于后备队列的作业中挑选一个(或多个)作业, 给他们分配内存等必要资源,并建立相应的进程(建立PCB),以使它(们)获得竞争处理机的权 利。高级调度是辅存(外存)与内存之间的调度。每个作业只调入一次,调出一次。作业调入时会建 立相应的PCB,作业调出时才撤销PCB。高级调度主要是指调入的问题,因为只有调入的时机需要 操作系统来确定,但调出的时机必然是作业运行结束才调出。
中级调度: 引入了虚拟存储技术之后,可将暂时不能运行的进程调至外存等待。等它重新具备了运行条件且 内存又稍有空闲时,再重新调入内存。 这么做的目的是为了提高内存利用率和系统吞吐量。 暂时调到外存等待的进程状态为挂起状态。值得注意的是,PCB并不会一起调到外存,而是会常驻 内存。PCB中会记录进程数据在外存中的存放位置,进程状态等信息,操作系统通过内存中的PCB 来保持对各个进程的监控、管理。被挂起的进程PCB会被放到的挂起队列中。 中级调度(内存调度),就是要决定将哪个处于挂起状态的进程重新调入内存。 一个进程可能会被多次调出、调入内存,因此中级调度发生的频率要比高级调度更高。
暂时调到外存等待的进程状态为挂起状态(挂起态,suspend) 挂起态又可以进一步细分为就绪挂起、阻塞挂起两种状态 低级调度: 低级调度(进程调度),其主要任务是按照某种方法和策略从就绪队列中选取一个进程,将处理机分配给它。 进程调度是操作系统中最基本的一种调度,在一般的操作系统中都必须配置进程调度。 进程调度的频率很高,一般几十毫秒一次。
进程调度的时机切换与过程调度方式: 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待(例如:bounded waiting 等待法),有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用。
进程切换: 对原来运行进程各种数据的保存 对新的进程各种数据的恢复 (如:程序计数器、程序状态字、各种数据寄存器等处理机现场信息,这些信息一般保存在进程控制块)
调度算法的评价指标:
调度算法: 注:这几种算法主要关心对用户的公平性、平均周转时间、平均等待时间等评价系统整体性能的指标,但 是不关心“响应时间”,也并不区分任务的紧急程度,因此对于用户来说,交互性很糟糕。因此这三种算 法一般适合用于早期的批处理系统,当然,FCFS算法也常结合其他的算法使用,在现在也扮演着很重要的 角色。 注:比起早期的批处理操作系统来说,由于计算机造价大幅降低,因此之后出现的交互式操作系统(包括 分时操作系统、实时操作系统等)更注重系统的响应时间、公平性、平衡性等指标。而这几种算法恰好也 能较好地满足交互式系统的需求。因此这三种算法适合用于交互式系统。
概述: 进程具有异步性的特征。异步性是指,各并发执行的进程以各自 独立的、不可预知的速度向前推进。
同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某 些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作
我们把一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备(比如摄像头、打印机)都 属于临界资源。此外还有许多变量、数据、内存缓冲区等都属于临界资源。 对临界资源的访问,必须互斥地进行。互斥,亦称间接制约关系。进程互斥指当一个进程访问某临界资源 时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后, 另一个进程才能去访问临界资源。
临界区是进程中访问临界资源的代码段。 进入区和退出区是负责实现互斥的代码段。 临界区也可称为“临界段”。
为了实现对临界资源的互斥访问,同时保证系统整体性能,需要遵循以下原则: 空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区; 忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待; 有限等待。对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿); 让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。
进程互斥的软件实现方法
进程互斥的硬件实现方法:
问题: 进程互斥的四种软件实现方式(单标志法、双标志先检查、双标志后检查、Peterson算法) 进程互斥的三种硬件实现方式(中断屏蔽方法、TS/TSL指令、Swap/XCHG指令) 在双标志先检查法中,进入区的“检查”、“上锁” 操作无法一气呵成,从而导致了两 个进程有可能同时进入临界区的问题; 所有的解决方案都无法实现“让权等待”
方法: 用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互 斥、进程同步。 信号量其实就是一个变量 ,可以用一个信号量 来表示系统中某种资源的数量。
P(S)、V(S)操作: 一对原语:wait(S) 原语和 signal(S) 原语,可以把原语理解为我们自己写的函数,函数名分别为 wait和 signal,括号里的信号量 S 其实就是函数调用时传入的一个参数。 wait、signal 原语常简称为 P、V操作(来自荷兰语 proberen 和 verhogen)。因此,做题的时候常把wait(S)、signal(S) 两个操作分别写为 P(S)、V(S)。
用信号量机制实现进程互斥、同 步、前驱关系:
生产者消费者问题 多生产者-多消费者 吸烟者问题 读者-写者问题 哲学家进餐问题
为什么引入管程: 信号量机制存在的问题:编写程序困难、易出错 能不能设计一种机制,让程序员写程序时不需要再关注复杂的PV操作,让写代码更轻松呢? 1973年,Brinch Hansen 首次在程序设计语言 (Pascal)中引入了“管程”成分——一种高级同步机制
管程的定义和基本特征: 管程是一种特殊的软件模块,有这些部分组成:
局部于管程的共享数据结构说明;对该数据结构进行操作的一组过程;(“过程”其实就是“函数”)对局部于管程的共享数据设置初始值的语句;管程有一个名字。管程的基本特征:
局部于管程的数据只能被局部于管程的过程所访问;一个进程只有通过调用管程内的过程才能进入管程访问共享数据;每次仅允许一个进程在管程内执行某个内部过程。概念: 在并发环境下,各进程因竞 争资源而造成的一种互相等 待对方手里的资源,导致各 进程都阻塞,都无法向前推 进的现象,就是“死锁”。 发生死锁后若无外力干涉, 这些进程都将无法向前推进。
死锁、饥饿、死循环的区别:
死锁产生的必要条件: 互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。 像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待 这种资源)。 不剥夺条件:进程所获得的资源在未使用完之前,不能由 其他进程强行夺走,只能主动释放。 请求和保持条件:进程已经保持了至少一个资源,但又提 出了新的资源请求,而该资源又被其他进程占有,此时请 求进程被阻塞,但又对自己已有的资源保持不放。 循环等待条件:存在一种进程资源的循环等待链,链中的 每一个进程已获得的资源同时被下一个进程所请求。 注意!发生死锁时一定有循环等待,但是发生循环等 待时未必死锁(循环等待是死锁的必要不充分条件)
什么时候会发生死锁: 对系统资源的竞争。各进程对不可剥夺的资源(如打印机)的竞争可能引起死锁,对可剥夺的资 源(CPU)的竞争是不会引起死锁的。 进程推进顺序非法。请求和释放资源的顺序不当,也同样会导致死锁。例如,并发执行的进程P1、P2 分别申请并占有了资源 R1、R2,之后进程P1又紧接着申请资源R2,而进程P2又申请资源R1, 两者会因为申请的资源被对方占有而阻塞,从而发生死锁。 信号量的使用不当也会造成死锁。如生产者-消费者问题中,如果实现互斥的P操作在实现同步的 P操作之前,就有可能导致死锁。(可以把互斥信号量、同步信号量也看做是一种抽象的系统资 源) 总之,对不可剥夺资源的不合理分配,可能导致死锁。
死锁的处理策略: 预防死锁。破坏死锁产生的四个必要条件中的一个或几个。 避免死锁。用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法) 死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措施解除死锁
预防死锁:
如果把只能互斥使用的资源改造为允许共享使用,则系统不会进入死锁状态。比如: SPOOLing技术。 操作系统可以采用 SPOOLing 技术把独占设备在逻辑上改造成共享设备。比如,用SPOOLing技术将打 印机改造为共享设备。 该策略的缺点:并不是所有的资源都可以改造成可共享使用的资源。并且为了系统安全,很多地方 还必须保护这种互斥性。因此,很多时候都无法破坏互斥条件。
避免死锁:
银行家算法是荷兰学者 Dijkstra 为银行系统设计的,以确保银行在发放现金贷款时,不会发生不能 满足所有客户需要的情况。后来该算法被用在操作系统中,用于避免死锁。 核心思想:在进程ᨀ出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进 入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待。
死锁的检测和解除: 如果系统中既不采取预防死锁的措施,也不采取避免死锁的措施,系统就很可能发生死锁。在这种 情况下,系统应当提供两个算法: ①死锁检测算法:用于检测系统状态,以确定系统中是否发生了死锁。 ②死锁解除算法:当认定系统中已经发生了死锁,利用该算法可将系统从死锁状态中解脱出来。