操作系统1
一、相关概念
1.操作系统的作用(什么是操作系统)
操作系统是指控制和管理整个计算机系统硬件和软件资源并合理的组织调度计算机工作和资源的分配,以提供用户和其它软件方便的接口和环境的程序集和。
对于用户来说,操作系统作用是方便使用,控制软件,管理应用程序;对于系统来说,操作系统是资源分配器。
2.计算机组成(冯诺依曼体系)
运算器:用于完成各种算术运算、逻辑运算和数据传送等数据加工处理。
控制器:用于控制程序的执行。
存储器:用于记忆程序和数据。
输入设备:用于将数据或程序输入到计算机中。
输出设备:将数据或程序的处理结果展示给用户。
3.操作系统的中断、异常和系统调用
中断:来源于不同的硬件设备和网络中断。中断是实现“用户态-》核心态”的唯一途径,而实现“核心态-》用户态”通过一条特权指令(将程序状态字寄存器PSW改为核心态,0是用户态,1是核心态)可以实现。
【分类】内中断(异常、例外、陷入):信号来源:CPU内部与当前执行的指令相关,例如自愿中断:陷入(有意而为之的异常,如系统调用),强迫中断:缺页,整数除0等;
外中断(中断):信号来源:CPU外部与当前执行的指令无关:例如外设请求:I/O完成后发出结束中断,人工干预:用户强制结束终止;
系统调用:是操作系统提供给应用程序使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序可以发出系统调用请求操作系统服务。在用户程序中,凡是和系统资源相关的操作都必须通过系统调用向操作系统请求服务。例如设备启动、请求和释放,文件的读写、创建和删除,进程的创建、撤销、阻塞和唤醒,进程之间的消息传递或信号传递等。系统调用的相关处理需要在核心态处理。
异常:非法指令或者其他坏的处理状态。
来源 | 处理时间 | 响应 | |
中断 | 外部设备 | 异步 | 持续,对用户应用程序是透明的 |
系统调用 | 应用程序主动请求 | 同步或异步 | 杀死或者继续执行意想不到的指令 |
异常 | 应用程序想不到的行为 | 同步 | 等待或持续 |
4. 系统调用与库函数的区别?#
A.系统调用是最底层的应用,是面向硬件的。而库函数的调用是面向开发的,相当于应用程序的API(即预先定义好的函数)接口;
B.各个操作系统的系统调用是不同的,因此系统调用一般是没有跨操作系统的可移植性,而库函数的移植性良好(c库在Windows和Linux环境下都可以操作);
C.库函数属于过程调用,调用开销小;系统调用需要在用户空间和内核上下文环境切换,开销较大;
D.库函数调用函数库中的一段程序,这段程序最终还是通过系统调用来实现的;系统调用调用的是系统内核的服务。
函数库调用 | 系统调用 |
---|---|
在所有的ANSI C编译器版本中,C库函数是相同的 | 各个操作系统的系统调用是不同的 |
它调用函数库中的一段程序(或函数) | 它调用系统内核的服务 |
与用户程序相联系 | 是操作系统的一个入口点 |
在用户地址空间执行 | 在内核地址空间执行 |
它的运行时间属于“用户时间” | 它的运行时间属于“系统”时间 |
属于过程调用,调用开销较小 | 需要在用户空间和内核上下文环境间切换,开销较大 |
在C函数库libc中有大约300个函数 | 在UNIX中大约有90个系统调用 |
典型的C函数库调用:system fprintf malloc | 典型的系统调用:chdir fork write brk; |
5.操作系统特征
并发:指两个或多个事件同一时间间隔发生,微观上这些程序还是在分时地交替进行(并行:同一时刻发生)。
共享:内存中并发执行的进程都可以使用系统中的资源(互斥共享或同时访问)。
虚拟:指把一个物理上的实体变成若干个逻辑上的对应物。(空间复用技术、时分复用技术)。
异步:在多道程序环境下,允许多个程序并发执行,但是由于资源有限,进程的执行不是一贯到底的,而是走走停停,以不可预知的速度前进。
6.操作系统分类(发展)
手工操作阶段
批处理阶段:多道性、无序性、调度性,系统利用率高、吞吐量大、平均周转时间长、但无交互能力。
分时操作系统:有多路性、独立性、及时性和交互性。 有较好的人机交互的特性,并且可以实现共享主机。
实时操作系统:有多路性、独立性、及时性、交互性和可靠性。实际上是指操作系统工作时,其各种资源可以根据需要随时进行动态分配。由于各种资源可以进行动态分配,因此,其处理事务的能力较强、速度较快。从可靠性:实时系统更强,从交互性:分时系统更强。
网络操作系统:
分布式操作系统:
个人计算机操作系统:Windows,Linux,MaxOS
7.操作系统运行机制
用户 | 用户 |
应用程序 | |
非内核功能 | |
进程管理、存储器管理、设备管理等 | |
时钟管理、中断机制、原语(设备驱动、CPU切换等) | |
裸机(纯硬件) |
内核是计算机配置地底层软件,实现操作系统内核功能的程序就是内核程序。
原语具有原子性,执行期间不允许中断,原语是采用关中断指令和开中断指令实现的,且权限非常大,只允许在核心态下执行的特权指令。
8.操作系统体系结构
大内核(上图3,4行):将操作系统主要功能模块都作为系统内核运行在核心态=》性能高,但是代码庞大结构混乱,难以维护
微内核(上图4行):只是把最基本的功能保留在内核=》功能少,结构清晰,易维护。但是需要在用户态和核心态之间切换,性能低。
9.操作系统基本功能
进程管理:进程控制、进程同步、进程通信、死锁处理、处理机调度等。
内存管理:内存分配、地址映射、内存保护与共享、虚拟内存等。
文件管理:文件存储空间的管理、目录管理、文件读写管理和保护等。
设备管理:完成用户的 I/O 请求,方便用户使用各种设备,并提高设备的利用率。主要包括缓冲管理、设备分配、设备处理、虛拟设备等。
10.1 概念#
进程:是程序的一次执行过程,是一个程序及数据在处理机上顺序执行时所发生的活动,是系统进行资源分配和调度的一个独立单位。由进程控制块PCB、程序段、数据段组成。进程是为了更好的使多道程序并发执行,以提高资源利用率,增加并发程度。
线程:最直接的理解是“轻量级进程”,是一个基本的CPU执行单元,比进程更小的独立运行的基本单位,也是程序执行流的最小单元。由线程ID、程序计数器、寄存器集合、堆栈 组成。线程是为了减少程序在并发执行时所付出的时空开销,提高操作系统的并发性能。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
一个程序至少一个进程,一个进程至少一个线程。例如QQ和浏览器是两个进程,但是分别由有许多自己的线程。
10.2 为什么会有线程?#
每个进程都有自己的地址空间,即进程空间,在网络或多用户换机下,一个服务器通常需要接收大量不确定数量用户的并发请求,为每一个请求都创建一个进程显然行不通(系统开销大响应用户请求效率低),因此操作系统中线程概念被引进。同一进程间的线程通信不需要系统干预。
- 线程的执行过程是线性的,尽管中间会发生中断或者暂停,但是进程所拥有的资源只为改线状执行过程服务,一旦发生线程切换,这些资源需要被保护起来。
- 进程分为单线程进程和多线程进程,单线程进程宏观来看也是线性执行过程,微观上只有单一的执行过程。多线程进程宏观是线性的,微观上多个执行操作。
- 线程的改变只代表CPU的执行过程的改变,而没有发生进程所拥有的资源的变化。
10.3 进程线程的区别?#
Ⅰ 拥有资源:进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。
Ⅱ 调度:线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。
Ⅲ 系统开销:由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。
Ⅳ 通信方面:线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 进程间通信IPC。
Ⅴ 并发性:进程和线程都可以并发执行。
Ⅵ 地址空间和其他资源:进程的地址空间之间互相独立,同一进程的各线程之间共享进程的资源,某进程内的线程对于其他进程不可见。
多线程之间同步机制:
临界区:不可以跨进程,忘记解锁会无限等待,要么存在要么没有,多线程访问独占性共享资源
互斥量:可以跨进程,忘记解锁会自动释放,要么存在要么没有
事件:又叫线程触发器,不可以跨进程,要么存在要么没有,一个线程来唤醒另一个线程(包括自动和人工两种方式)
信号量:可以跨进程,始终代表可用资源数量,当资源数为o时,线程阻塞,允许多个线程同时访问一个共享资源
10.4 优缺点#
- 线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。
- 进程执行开销大,但是能够很好的进行资源管理和保护。进程可以跨机器前移。
10.5 何时使用多进程,何时使用多线程?#
- 对资源的管理和保护要求高,不限制开销和效率时,使用多进程。
- 要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。
10.6 进程控制块PCB作用
11. 进程有哪几种状态?#
- 就绪状态:进程已获得除处理机以外的所需资源,等待分配处理机资源。
- 运行状态:占用处理机资源运行,处于此状态的进程数小于等于CPU数。
- 阻塞状态: 进程等待某种条件,在条件满足之前无法执行。
- 阻塞==》就绪:进程等待的事件来时,满足条件; 就绪==》运行:进程被调度,获得处理机资源;
- 运行==》阻塞:当进程请求某一资源的使用和分配,或等待某一事件的发生。 运行==》就绪:进程在时间片用完后让出处理机,或当有更高优先级的进程就绪时。
11.1 线程有几种状态
12. 线程同步的方式及原因?#
- 互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
- 信号量:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
- 事件(信号):通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。
13. 线程间的通信机制?#
进程通信指的是进程之间的信息交换。进程是分配系统资源的单位,因此各进程拥有的内存地址空间相互独立,为了保证安全,进程不能直接访问另一个进程的地址空间。
-
管道及命名管道:管道可用于具有亲缘关系的父子进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;(管道半双工通信)无名管道简单方便,但是单向且亲缘关系。命名管道长期存在于系统中容易出错。
- 信号:信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
- 消息队列:消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息;在进行通信的时候不用考虑同步的问题,但是需要复制队列中的消息,不适合信息量大且操作频繁的场合。
- 共享内存:可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等;直接在内存共享信息,无需复制,但是是基于进程虚拟地址空间进行的,进程读写操作的同步问题操作系统无法实现。
- 信号量:主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段;不用交换大批数据,常作为锁机制。
-
套接字:这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。
14.进程的组织方式
1.链接方式:按照进程状态将PCB分为多个队列,操作系统持有各个队列的指针。
2.索引方式:按照进程状态将PCB建立几张索引表,操作系统持有各个索引表的指针。
14.1. 线程调度和进程调度
https://mp.weixin.qq.com/s/tDfMAshpUr2N6absPR7Dug
14.2 协程
https://www.cnblogs.com/tohxyblog/p/10712798.html
协程,则是基于线程之上的,自主开辟的异步任务,很多人更喜欢叫它们纤程(Fiber),或者绿色线程(GreenThread)。
协程的特点:
- 线程的切换由操作系统负责调度,协程由用户自己进行调度,因此减少了上下文切换。
- 线程的默认Stack大小是1M,而协程更轻量,接近1K。因此可以在相同的内存中开启更多的协程。
- 由于在同一个线程上,因此可以避免竞争关系而使用锁。
14.3 CPU上下文切换资源
https://www.cnblogs.com/Sargreis/p/6874866.html
https://www.jianshu.com/p/4393a4537eca
1. CPU上下文:CPU在运行任何任务前必须依赖的环境成为CPU上下文。其中: CPU寄存器:是CPU内置的容量小、速度极快的内存。程序计数器:用来存储CPU正在执行的指令位置,或者执行的下一条指令的位置。(这两个保存至内核中)
2. CPU上下文切换:就是先把前一个任务的CPU寄存器和程序计数器保存下来,然后加载新任务的CPU寄存器和计数器的过程。
3.1 进程上下文切换
1. 先了解系统调用概念:从用户态到内核态的转换过程称为系统调用。发生系统调用是需要触发两次CPU上下文切换(用户态-》内核态,内核态-》用户态)。
2. 系统调用和进程上下文切换的区别
- 系统调用都是在同一个进程中发生
- 进程上下文切换是从一个进程切换到第二个进程中运行
- 进程是由内核来进行管理和调度的,现成的切换只能发生在内核态。进程上下文切换除了需要保存 虚拟内存,栈,全局变量 等用户空间的资源,还包括 内核堆栈,寄存器等内核空间的状态
3. 触发进程调度的情景
- 进程时间片用完,系统进行调度
- 进程申请的系统资源不足(比如内存不足)
- 调用 Sleep 函数主动挂起进程
- 当有优先级更高的进程运行时,CPU上的进程会被挂起
3.2 线程上下文切换
- 当进程只有一个线程时,可以认为进程就等于线程。
- 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时是不需要修改的。
- 另外,线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时也是需要保存的。
2. 第二种,前后两个线程属于同一个进程,此时,应为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据,寄存器等不共享的数据。
3.3 中断上下文切换
中断优于进程的正常调度和执行。
如何避免?
- 无锁并发编程: 多线程竞争锁时,会引起上下文切换,所以多线程处理数据的时候,可以采用一些办法来避免使用锁,如将数据的ID按照Hash算法分段,不同的线程处理不同的数据。(这和操作系统对内存的管理有一些相似,即内存隔离)
- CAS算法,Java的Atomic包使用CAS算法来更新数据,不需要加锁。
- 使用最少线程。避免创建不必要的线程,线程池也得有一定的大小,可以用一个BlockingQueue来维护事件。
- 协程:在单线程里实现多任务的调度,并在单线程维持多个任务切换。
15. 守护、僵尸、孤儿进程的概念?#
15.1 基本概念#
-
在类UNIX系统中,僵尸进程是指完成执行(通过 exit 系统调用,或运行时发生致命错误或收到终止信号所致)但在操作系统的进程表中仍然有一个表项(进程控制块PCB),处于"终止状态 "的进程。
-
在一个多工的电脑作业系統中,守护进程是一种在后台执行的电脑程序。 此类程序会被以进程的形式初始化。 守护进程程序的名称通常以字母“d”结尾:例如,syslogd就是指管理系统日志的守护进程。
- 在操作系统领域中,孤儿进程指的是在其父进程执行完成或被终止后仍继续运行的一类进程。
个人理解:
-
一般情况下,子进程是由父进程创建,而子进程和父进程的退出是无顺序的,两者之间都不知道谁先退出。正常情况下父进程先结束会调用 wait 或者 waitpid 函数等待子进程完成再退出,而一旦父进程不等待直接退出,则剩下的子进程会被init(pid=1)进程接收,成会孤儿进程。(进程树中除了init都会有父进程)。
-
如果子进程先退出了,父进程还未结束并且没有调用 wait 或者 waitpid 函数获取子进程的状态信息,则子进程残留的状态信息( task_struct 结构和少量资源信息)会变成僵尸进程。
-
守护进程( daemon) 是指在后台运行,没有控制终端与之相连的进程。它独立于控制终端,通常周期性地执行某种任务 。 守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断 。
15.2 危害#
孤儿进程结束后会被 init 进程善后,并没有危害,而僵尸进程则会一直占着进程号,操作系统的进程数量有限则会受影响。
15.3 解决#
一般僵尸进程的产生都是因为父进程的原因,则可以通过 kill 父进程解决,这时候僵尸进程就变成了孤儿进程,被 init 进程接收
16. 什么是死锁?死锁产生的条件?如何避免死锁★★#
#
多个进程在运行过程中因争夺资源而造成的一种僵局。当一个进程请求资源时,如果该资源不能立即获得,那么进程就会进入等待状态。如果一个处于等待状态的进程 P1,由于所等待的资源被另一个处于等待状态的进程 p2 所占有,而 p2 所请求的资源又被 p1 占有,这样它们所请求的资源都不会获得,两进程一直处于等待状态,形成死锁。
16.1 死锁产生的原因?#
- 因为系统资源不足。
- 进程运行推进的顺序不合适。
- 资源分配不当等。
16.2 死锁产生的条件?#
- (1)互斥条件:资源不能被共享,只能由一个进程使用。(吃独食,桌子上只能有我)
- (2)请求与保持条件(占有和等待):已经得到资源的进程可以再次申请新的资源。(贪吃)
- (3)非剥夺条件:已经分配的资源不能从相应的进程中被强制地剥夺。(不给别人吃)
- (4)循环等待条件:系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。(吃别人的)
16.3 死锁的处理
1.死锁的预防
A.打破互斥条件:改造独占性资源为虚拟资源,大部分资源已无法改造。(饭都可以吃)
B.打破不可抢占条件:当一进程占有一独占性资源后又申请一独占性资源而无法满足,则退出原占有的资源。(支持自己的)
C.打破占有且申请条件:采用资源预先分配策略,即进程运行前申请全部资源,满足则运行,不然就等待,这样就不会占有且申请。(要吃多少先给多少)
D.打破循环等待条件:实现资源有序分配策略,对所有设备实现分类编号,所有进程只能采用按序号递增的形式申请资源。(分配吃饭)
2.避免死锁
安全序列指如果系统按照这种序列分配资源,则每个进程都能顺利完成,只要能找出一个安全序列,系统就是安全状态。
3.死锁的检测和解除
【检测】
A.每种类型一个资源的死锁检测
上图为资源分配图,其中方框表示资源,圆圈表示进程。资源指向进程表示该资源已经分配给该进程,进程指向资源表示进程请求获取该资源。图 a 可以抽取出环,如图 b,它满足了环路等待条件,因此会发生死锁。每种类型一个资源的死锁检测算法是通过检测有向图是否存在环来实现,从一个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到死锁的发生。
B.每种类型多个资源的死锁检测
上图中,有三个进程四个资源,每个数据代表的含义如下:
- E 向量:资源总量
- A 向量:资源剩余量
- C 矩阵:每个进程所拥有的资源数量,每一行都代表一个进程拥有资源的数量
- R 矩阵:每个进程请求的资源数量
进程 P1 和 P2 所请求的资源都得不到满足,只有进程 P3 可以,让 P3 执行,之后释放 P3 拥有的资源,此时 A = (2 2 2 0)。P2 可以执行,执行后释放 P2 拥有的资源,A = (4 2 2 1) 。P1 也可以执行。所有进程都可以顺利执行,没有死锁。
算法总结如下:每个进程最开始时都不被标记,执行过程有可能被标记。当算法结束时,任何没有被标记的进程都是死锁进程。
- 寻找一个没有标记的进程 Pi,它所请求的资源小于等于 A。
- 如果找到了这样一个进程,那么将 C 矩阵的第 i 行向量加到 A 中,标记该进程,并转回 1。
- 如果没有这样一个进程,算法终止。
【解除】
A.资源剥夺法:挂起(暂时放到外存中)一部分死锁进程,并抢占他们的资源分给其他死锁进程。
B.撤销进程法:强制撤销部分甚至全部死锁进程,并剥夺这些进程资源。
C.进程回退法:让一个或多个进程回退到不发生思索的状态。
17. 操作系统的调度算法有哪些?#
- 先来先服务(FCFS):此算法的原则是按照作业到达后备作业队列(或进程进入就绪队列)的先后次序选择作业(或进程)。(对长作业有利,饥饿)(批处理操作系统)
- 短作业优先(SJF:Shortest Process First):这种算法主要用于作业调度,它从作业后备序列中挑选所需运行时间最短的作业进入主存运行。(对短作业有利,饥饿)(批处理操作系统)
- 时间片轮转调度算法:当某个进程执行的时间片用完时,调度程序便终止该进程的执行,并将它送到就绪队列的末尾,等待分配下一时间片再执行。然后把处理机分配给就绪队列中新的队首进程,同时也让它执行一个时间片。这样就可以保证队列中的所有进程,在已给定的时间内,均能获得一时间片处理机执行时间。(不会饥饿)(分时操作系统)
- 高响应比优先:按照高响应比(已等待时间+要求运行时间)/要求运行时间 优先的原则,在每次选择作业投入运行时,先计算此时后备作业队列中每个作业的响应比RP。选择最大的作业投入运行。(不会饥饿)
- 优先权调度算法:按照进程的优先权大小来调度。使高优先权进程得到优先处理的调度策略称为优先权调度算法。注意:优先数越多,优先权越小。(分时操作系统)
- 多级队列调度算法:多队列调度是根据作业的性质和类型的不同,将就绪队列再分为若干个队列,所有的作业(进程)按其性质排入相应的队列中,而不同的就绪队列采用不同的调度算法。(分时操作系统)
18.处理机调度层次
《处理机调度就是对处理机进行分配,就是从就绪队列中按照一定的算法选择一个进程并将处理机分配给它运行以实现进程并发执行。》
1.高级(作业)调度: 主要用于多道批处理系统中,又称长作业调度,调度队像是作业,根据某种算法决定将后备队列中的哪几个作业调入内存。
2.中级(内存)调度:操作系统中最基本的一种调度方式(频率最高),在多道批处理、分时和时实三中类型的OS中都存在,又称为短作业调度。
3.低级(进程)调度:又称为内存调度,目的是为了提高内存的利用率和系统的吞吐率。
19.什么时候不能进行进程间的切换
1.处理中断的过程中:中断处理过程复杂,在实际上难以做到进程切换。而且中断是系统工作的一部分,不属于某一进程,不应该剥夺处理机资源。
2.进程在内核程序临界区中:只允许一个进程独占共享资源。
3.原子操作过程中:如加锁、解锁、中断现场保护、恢复等原子操作。
20.进程同步
进程具有异步性,各并发执行的进程以各自独立的不可预知的速度向前推进。进程同步也成为直接制约关系,它是指未完成某项任务而建立的多个进程,需要按照某种次序执行,相互制约,相互合作。(进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。)
21.进程(互斥)原则(什么是临界区,如何解决冲突)
每个进程中访问临界资源的那段程序称为临界区,每次只准许一个进程进入临界区,进入后不允许其他进程进入。
1.空闲让进:临界区空闲时就允许一个请求进入临界区。(厕所空的)
2.忙则等待:保证对临界区的互斥访问。(有人正在上厕所)
3.有限等待:有限代表有限的时间内进入临界区,避免死等饥饿。(有人只能憋一分钟)
4.让权等待:当进程不能进入自己的临界区时,应该释放处理机,以免陷入忙等状态。(自己上厕所没带纸不能上,先让别人上)
22.进程互斥实现方法
软件实现
1.单标志法:两个进程在访问临界区后会把使用临界区的权限转交给另一个进程,每个进程进入临界区的权限只能被另一个进程赋予。违反空闲让进原则,自己不去厕所也不让别人去。
2.双标志先检查:设置一个boolean数组,数组中各个元素用来标记个进程想进入临界区的意愿。违反忙则等待原则,检查和上锁不是一气呵成的,两个人都想上厕所。
3.双标志后检查:先上锁后检查。违反空闲让进和有限等待原则。
4.Peterson算法:在进入区检查对方是否想进,自己是否谦让。违反让权等待原则。
硬件实现
1.中断屏蔽方法:利用开/关中断指令。简单高效,只适合单处理机。
2.TestAndSet(TS指令/TSL指令):TSL指令是用硬件实现的,执行的过程不允许中断,只能一气呵成。适用于多处理机环境,但是不满足让权等待原则。
3.Swap指令(XCHG指令):Swap指令使用硬件实现的,执行过程不允许中断。
23.信号量
信号量是一个整型变量,可以对其执行 down 和 up 操作,也就是常见的 P 和 V 操作。
- down : 如果信号量大于 0 ,执行 -1 操作;如果信号量等于 0,进程睡眠,等待信号量大于 0;
- up :对信号量执行 +1 操作,唤醒睡眠的进程让其完成 down 操作。
down 和 up 操作需要被设计成原语,不可分割,通常的做法是在执行这些操作的时候屏蔽中断。如果信号量的取值只能为 0 或者 1,那么就成为了 互斥量(Mutex) ,0 表示临界区已经加锁,1 表示临界区解锁。
信号量实现进程互斥:设置互斥信号量初值为1,临界区之前对信号量执行P操作,临界区之后对信号量执行V操作。前P后V
信号量实现进程同步:设置同步信号量初值为0,临界区之前对信号量执行V操作,临界区之后对信号量执行P操作。前V后P
24.使用信号量实现生产者-消费者问题
问题描述:使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品;只有缓冲区不为空,消费者才可以拿走物品。
因为缓冲区属于临界资源,因此需要使用一个互斥量 mutex 来控制对缓冲区的互斥访问。
为了同步生产者和消费者的行为,需要记录缓冲区中物品的数量。数量可以使用信号量来进行统计,这里需要使用两个信号量:empty 记录空缓冲区的数量,full 记录满缓冲区的数量。其中,empty 信号量是在生产者进程中使用,当 empty 不为 0 时,生产者才可以放入物品;full 信号量是在消费者进程中使用,当 full 信号量不为 0 时,消费者才可以取走物品。
注意,不能先对缓冲区进行加锁,再测试信号量。也就是说,不能先执行 down(mutex) 再执行 down(empty)。如果这么做了,那么可能会出现这种情况:生产者对缓冲区加锁后,执行 down(empty) 操作,发现 empty = 0,此时生产者睡眠。消费者不能进入临界区,因为生产者对缓冲区加锁了,消费者就无法执行 up(empty) 操作,empty 永远都为 0,导致生产者永远等待下,不会释放锁,消费者因此也会永远等待下去。
25.哲学家问题
五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。
如果所有哲学家同时拿起左手边的筷子,那么所有哲学家都在等待其它哲学家吃完并释放自己手中的筷子,导致死锁。为了防止死锁的发生,可以设置两个条件:必须同时拿起左右两根筷子;只有在两个邻居都没有进餐的情况下才允许进餐;
26.读者-写者问题
允许多个进程同时对数据进行读操作,但是不允许读和写以及写和写操作同时发生。一个整型变量 count 记录在对数据进行读操作的进程数量,一个互斥量 count_mutex 用于对 count 加锁,一个互斥量 data_mutex 用于对读写的数据加锁。
27.管程
使用信号量机制实现的生产者消费者问题需要客户端代码做很多控制,而管程把控制的代码独立出来,不仅不容易出错,也使得客户端代码调用更容易。管程有一个重要特性:在一个时刻只能有一个进程使用管程(类似于Java方法被Synchronized修饰)。进程在无法继续执行的时候不能一直占用管程,否则其它进程永远不能使用管程。管程引入了 条件变量 以及相关的操作:wait() 和 signal() 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来给另一个进程持有。signal() 操作用于唤醒被阻塞的进程。
28.
1.磁盘结构
- 盘面(Platter):一个磁盘有多个盘面;
- 磁道(Track):盘面上的圆形带状区域,一个盘面可以有多个磁道;
- 扇区(Track Sector):磁道上的一个弧段,一个磁道可以有多个扇区,它是最小的物理储存单位,目前主要有 512 bytes 与 4 K 两种大小;
- 磁头(Head):与盘面非常接近,能够将盘面上的磁场转换为电信号(读),或者将电信号转换为盘面的磁场(写);
- 制动手臂(Actuator arm):用于在磁道之间移动磁头;
- 主轴(Spindle):使整个盘面转动。
2.磁盘调度算法
读写速度影响因素:旋转时间(主轴转动盘面,使得磁头移动到适当的扇区上);寻道时间(制动手臂移动,使得磁头移动到适当的磁道上);实际的数据传输时间;其中,寻道时间最长,因此磁盘调度的主要目标是使磁盘的平均寻道时间最短。
(1)先来先服务算法:按照磁盘请求的顺序进行调度。优点是公平和简单。缺点也很明显,因为未对寻道做任何优化,使平均寻道时间可能较长。
(2)最短寻道时间优先算法:优先调度与当前磁头所在磁道距离最近的磁道。
(3)电梯算法:电梯总是保持一个方向运行,直到该方向没有请求为止,然后改变运行方向。电梯算法(扫描算法)和电梯的运行过程类似,总是按一个方向来进行磁盘调度,直到该方向上没有未完成的磁盘请求,然后改变方向。因为考虑了移动方向,因此所有的磁盘请求都会被满足,解决了 SSTF 的饥饿问题。
1.虚拟内存
目的:为了让物理内存扩充成更大的逻辑内存,就是让实际大小的内存发挥更大的存储作用。
为了更好地管理内存,操作系统实际内存抽象成地址空间,每个程序都有自己的地址空间,这个地址空间被分割成多块,每块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有的页都必须在物理内存中。当程序引用到不在物理内存的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。
综上,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能。
2. 分页系统地址映射
内存管理单元(MMU)管理着地址空间和物理内存的转换,其中的页表(Page table)存储着页(程序地址空间)和页框(物理内存空间)的映射表。
一个虚拟地址分成两个部分,一部分存储页面号,一部分存储偏移量。
下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。例如对于虚拟地址(0010 000000000100),前 4 位是存储页面号 2,读取页表项内容为(110 1),页表项最后一位表示是否存在于内存中,1 表示存在。后 12 位存储偏移量。这个页对应的页框的地址为 (110 000000000100)。
虚拟地址---前四位--》存储页面号-----》页表项(最后一位表示是否存于内存中)---后12位偏移量--》物理地址(页框)
3. 页面置换方法
在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。
① 最佳 (OPT):所选择的被换出的页面将是最长时间内不再被访问。(未来情况不可确定)
② 最近最久未使用(LRU):
③ 最近未使用(NRU):优先换出已经被修改的脏页面(R=0,M=1).
每个页面都有两个状态位:R 与 M,当页面被访问时设置页面的 R=1,当页面被修改时设置 M=1。其中 R 位会定时被清零。可以将页面分成以下四类:
- R=0,M=0
- R=0,M=1
- R=1,M=0
- R=1,M=1
④ 先进先出(FIFO):
⑤ 第二次机会算法:当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。
⑥ 时钟:第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。
4. 分段
虚拟内存采用的是分页技术,也就是将地址空间划分成固定大小的页,每一页再与内存进行映射。表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。
6.分页、分段比较
-
对程序员的透明性:分页透明,但是分段需要程序员显式划分每个段。
-
地址空间的维度:分页是一维地址空间,分段是二维的。
-
大小是否可以改变:页的大小不可变,段的大小可以动态改变。
-
出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。
7. 段页式
段页式存储组织是分段式和分页式结合的存储组织方法,这样可充分利用分段管理和分页管理的优点。
(1) 用分段方法来分配和管理虚拟存储器。程序的地址空间按逻辑单位分成基本独立的段,而每一段有自己的段名,再把每段分成固定大小的若干页。
(2) 用分页方法来分配和管理实存。即把整个主存分成与上述页大小相等的存储块,可装入作业的任何一页。程序对内存的调入或调出是按页进行的。但它又可按段实现共享和保护。
所选择的被换出的页面将是最长时间内不再被访问
法,因为无法知道一个页面多长时间不再被访问。