(1)无结构操作系统:
早期的操作系统没有真正意义上的“结构”可言,只是大量的过程的集合,过程之间可以互相调用,导致操作系统内部复杂而混乱。
(2)模块化结构操作系统:
模块化结构的 OS 基于程序模块化开发的思想,按照功能划分了多个具有一定独立性和大小的模块,每个模块有自己的功能,同时互相之间能够通过接口实现交互。模块之下又有子模块,以此类推。
模块化开发的 OS 虽然提高了 OS 设计的正确性、可理解性、可维护性,加速了开发过程,但是也存在着一定的问题:接口难以满足实际需求;多个决定齐头并进,呈现出“无序性”。
(3)分层式结构操作系统
为了将“无序性”转化成“有序性”,采用了自底向上方法,在目标系统和裸机(宿主)系统之间铺设多个中间层,使得目标系统最终得以在裸机系统上运行。
从层次来看,为了使每一步设计都建立在可靠的基础上(这正是模块化结构 OS 缺失的),规定每一层仅能使用其底层提供的功能和服务 —— 这就使得调试变得非常容易,比如调试 A2 层的时候,可以只考虑 A1 层,因为 A2 层依赖 A1 层的服务和功能。一层一层自底向上增添,每一层实现一些功能,最后构成一个完整的 OS。
聚焦于单个层次,每个层次都由若干个模块构成。
分层式结构的 OS 虽然保证了系统的正确性、可扩充性和易维护性,但是由于是分层单向依赖,使得层次和层次之间的通信成为了一个问题。执行一个简单的功能,可能需要穿越多个层次完成通信。
(1)足够小的内核:
包含 —— 与硬件处理紧密相关的部分;基本的功能;客户与服务器之间的通信
(2)基于客户/服务器模式 :
OS 最基本的部分放在内核中,其它绝大部分功能则在微内核外面的一组服务器(进程)中实现,比如 IO 设备管理服务器、进程服务器等。客户与服务器之间通过消息传递机制实现信息交互,如下图:
(3)应用“机制与策略分离”原理:
在微内核 OS 中,通常将机制放在 OS 的微内核中。
(4)采用面向对象技术:
基于“抽象”“隐蔽”原则控制系统的复杂性,基于“对象”“封装”“继承”确保系统的正确性、可靠性、易修改性、易扩展性。
优点 | 缺点 |
---|---|
提高了系统可扩展性 | 采用了小的内核 |
增强了系统的可靠性 | C/S模式和消息传递机制 |
较好的可移植性 | 运行效率有所降低 |
提供了对分布式系统的支持 | 传统 OS 只需进行两次变态,而微内核 OS 需进行多次变态(具体下文会提及) |
融入了面向对象技术 |
特权指令:
指的是有特殊权限的指令,比如:清内存、置时钟、分配系统资源、修改虚存的段表和页表,修改用户的访问权限等。这类指令使用不慎将导致系统崩溃,因此不能直接向用户程序开放使用这些指令的权限。
非特权指令:
相对于特权指令来说的普通指令,任何程序都可以使用,比如运算指令等。
CPU 的核心态或者用户态可以看作一种状态,一种模式或者一种级别。
**核心态(目态):**当处于核心态时,可以使用特权指令或者非特权指令(陷入指令是例外,它只能在用户态下执行)
**用户态(管态):**当处于用户态时,只能使用非特权指令
**内核程序:**运行在核心态下,可以执行特权指令
**应用程序:**运行在用户态下,为了系统安全着想,它只能执行非特权指令
先看计算机系统的结构层次:
重点在 OS 的内核,它是 OS 最基本、最核心的部分。
大内核:
如果内核不仅包括了时钟管理、中断处理以及原语(设备驱动、CPU 切换),还包含了进程管理、存储器管理以及设备管理等功能,那么就属于大内核。
大内核虽然使得内部代码非常庞大复杂,但是在用户态与核心态之间的切换,相对来说是很快的,这是因为大内核集成了进程管理、存储器管理等;
微内核:
如果内核仅由时钟管理、中断处理以及原语(设备驱动、CPU 切换)构成,那么这种内核属于微内核;
微内核的代码结构相对来说就很清晰、便于维护,但是由于微内核只集成了时钟管理、中断处理等这些最最基本的功能,所以在涉及到进程管理、存储器管理等时,就可能需要频繁变态(切换到用户态),而变态是需要消耗时间的,这无疑就会降低运行的性能。
在第一篇笔记中,我们说过,早期的操作系统只能串行跑程序,一个完成之后才能轮到下一个,这种情况下资源利用率显然是很低的;于是后来有了多道批处理系统,可以并发执行程序,为什么能够并发执行呢?这其实依赖于中断机制。
内中断(异常、例外、陷入):内中断的中断信号来自于 CPU 内部,和执行的指令有关
外中断(狭义的中断):外中断的中断信号来自于 CPU 外部,和执行的指令无关
此外,还有另一种分类方式:
我们用一个过程来演示中断的发生:
(Session 1)时间片用完了:
比方说,现在有个 A 进程正在用户态下运行。一段时间后,该进程消耗完了本次的时间片,那么操作系统内核中的计时部件知道时间到了,就会向 CPU 发射一个中断信号。CPU 接收到中断信号后,肯定要针对本次中断进行处理,但是它自己是无法处理的,需要借助操作系统内核的中断处理程序处理,而该程序又需要运行在核心态下,所以,此时 CPU 由一开始的用户态切换成了核心态。操作系统内核的中断处理程序针对中断信号进行处理,发现原来是 A 进程的时间片用完了,应该轮到 B 进程运行了,那么它就会把 CPU 使用权移交给 B 进程,让 B 进程开始运行,此时 CPU 也切换回用户态。
(Session 2)要进行输出:
B 进程正常运行,这时候执行到的某一行代码要求进行输出操作。前面我们说过,输入输出是特权指令,B 作为一个普通的用户程序来说,是不能直接执行特权指令的,因此,B 进程通过系统调用的方式向 CPU 发射一个中断信号,CPU 接收到中断信号后,肯定要针对本次中断进行处理,但是它自己是无法处理的,需要借助操作系统内核的中断处理程序处理,而该程序又需要运行在核心态下,所以,此时 CPU 由一开始的用户态切换成了核心态。操作系统内核的中断处理程序针对中断信号进行处理,发现原来是 B 进程要进行输出,那么它就会让打印机这一 I/O 设备开始工作。对于 B 进程,此时它要暂停运行,等待 I/O 完成。而这段空闲的时间不能浪费,所以操作系统就会把 CPU 使用权移交给 C 进程,让 C 进程开始运行,此时 CPU 也切换回用户态。
(Session 3)输出完成了:
现在,C 进程和 I/O 设备并发运行,在 I/O 设备搞定了自己的工作后,它会向 CPU 发射一个中断信号。一如既往地,CPU 再次变成核心态,操作系统介入,发现原来是输出工作完成了,应该让上次暂停的 B 进程继续运行了,那么它就会把 CPU 使用权再次移交给 B 进程,让 B 进程往后运行,此时 CPU 也切换回用户态。
操作系统作为连接 用户/应用程序 和 计算机硬件 的中间层,需要向上提供一些接口以方便用户或者应用程序使用它的服务,这些接口包括命令接口和程序接口。
命令接口即联机命令接口和脱机命令接口,用户可以直接使用这些接口;而程序接口则是由一组系统调用组成的,用户需要通过程序间接使用:
应用程序通过系统调用请求操作系统的服务。系统中的各种共享资源归操作系统管理,因此在用户程序中,凡是和资源相关的操作,都必须通过系统调用的方式向操作系统提出服务请求,由操作系统代为完成,从而保证系统的稳定性和安全性,防止用户进行非法操作。
这些功能都涉及到了特权指令,因此系统调用虽然是在用户态发出的,但是他的处理是需要在核心态下完成的。
PS:部分的库函数是对系统调用的封装
的 分配/回收 等
这些功能都涉及到了特权指令,因此系统调用虽然是在用户态发出的,但是他的处理是需要在核心态下完成的。
PS:部分的库函数是对系统调用的封装
传递系统调用的参数 ==> 在用户态下执行陷入指令,发生内中断,进入核心态 ==> 在核心态下执行系统调用相应服务程序 ==> 返回用户程序