练习题

基础概念练习题

1. 操作系统的基本特征

题目:简述操作系统的四个基本特征,并说明它们之间的关系。

异步

解题思路:

四个特征要逐个说清含义,最后落到它们之间的关系上:并发与共享互为条件,虚拟为并发共享提供技术基础,异步是并发执行的必然结果。

详细步骤:

操作系统的四个基本特征是:

  1. 并发性(Concurrency)

    • 多个程序或进程在同一时间段内同时执行
    • 通过时间片轮转实现并发
    • 提高系统资源利用率
  2. 共享性(Sharing)

    • 系统中的资源可以被多个并发执行的程序共同使用
    • 包括互斥共享和同时共享两种方式
    • 涉及 CPU 时间、内存空间、外设等资源
  3. 虚拟性(Virtualization)

    • 通过某种技术将一个物理实体转换为多个逻辑对应物
    • 包括 CPU 虚拟化、内存虚拟化、设备虚拟化
    • 为用户提供比实际硬件更多的资源
  4. 异步性(Asynchronism)

    • 程序的执行不是一气呵成的,而是走走停停
    • 以不可预知的速度向前推进
    • 需要同步机制保证正确性

关系:

  • 并发性和共享性相互促进,并发执行需要资源共享
  • 虚拟性为并发和共享提供了技术基础
  • 异步性是并发执行的自然结果

最终答案:

四个基本特征是并发性、共享性、虚拟性、异步性。并发与共享相互促进——并发执行需要资源共享;虚拟性为并发和共享提供技术基础;异步性是并发执行的自然结果,程序的执行走走停停、速度不可预知,需要同步机制保证正确性。

2. 操作系统的发展历程

题目:请按时间顺序列出操作系统的发展阶段,并说明每个阶段的主要特点。

分时系统

解题思路:

按时间线把各阶段排开,每个阶段记住「谁在管、CPU 利用率怎么样、人机关系如何」三条主线,再指出每个阶段引入的关键技术。

详细步骤:

  1. 第一代:人工操作阶段(1945-1955)

    • 没有操作系统
    • 程序员直接操作机器
    • CPU 利用率极低(小于 5%)
    • 串行处理,效率极低
  2. 第二代:批处理系统(1955-1965)

    • 引入监督程序(Monitor)
    • 批量处理作业
    • 提高 CPU 利用率
    • 减少人工干预
  3. 第三代:分时系统(1965-1980)

    • 多用户同时使用
    • 时间片轮转
    • 交互式操作
    • 资源共享
  4. 第四代:实时系统(1980-1990)

    • 实时响应
    • 确定性
    • 可靠性高
    • 专用性强
  5. 第五代:网络操作系统(1990-2000)

    • 网络连接
    • 分布式处理
    • 资源共享
    • 通信协议
  6. 第六代:分布式操作系统(2000-2010)

    • 多计算机协同
    • 透明性
    • 容错性
    • 可扩展性
  7. 第七代:嵌入式操作系统(2010-至今)

    • 专用性强
    • 资源受限
    • 实时性要求
    • 功耗优化

最终答案:

阶段依次为:人工操作阶段(无操作系统、CPU 利用率极低、串行处理)、批处理系统(引入监督程序、批量处理作业、提升 CPU 利用率)、分时系统(多用户同时使用、时间片轮转、交互式操作、资源共享)、实时系统(实时响应、确定性、可靠性高、专用性强)、网络操作系统(网络连接、分布式处理、资源共享、通信协议)、分布式操作系统(多计算机协同、透明性、容错性、可扩展性)、嵌入式操作系统(专用性强、资源受限、实时性要求、功耗优化)。

3. 内核态与用户态

题目:解释内核态和用户态的区别,并说明它们之间的切换机制。

系统调用

解题思路:

先从权限维度对比两种状态,再把切换的触发条件和切换动作分开说:进入内核态靠系统调用/中断/异常/特权指令,返回用户态靠系统调用返回或中断处理结束。

详细步骤:

内核态(Kernel Mode):

  • 最高权限级别
  • 可以执行所有指令
  • 直接访问硬件
  • 可以修改系统状态
  • 典型操作:内存管理、进程调度、设备驱动

用户态(User Mode):

  • 较低权限级别
  • 只能执行非特权指令
  • 不能直接访问硬件
  • 受系统保护
  • 典型操作:应用程序执行、用户数据处理

切换机制:

用户态到内核态的切换:

  • 触发条件:系统调用、中断、异常、特权指令
  • 切换过程:保存用户态上下文 -> 切换到内核态 -> 执行内核代码

内核态到用户态的切换:

  • 触发条件:系统调用返回、中断处理完成、异常处理完成
  • 切换过程:恢复用户态上下文 -> 切换到用户态 -> 继续用户程序

最终答案:

内核态是最高权限级别,可执行所有指令、直接访问硬件、修改系统状态,承担内存管理、进程调度与设备驱动;用户态权限较低,只能执行非特权指令、不能直接访问硬件、受系统保护,用于执行应用程序与处理用户数据。用户态到内核态由系统调用、中断、异常或特权指令触发,过程是保存用户态上下文、切换到内核态、执行内核代码;内核态到用户态由系统调用返回、中断处理完成或异常处理完成触发,过程是恢复用户态上下文、切回用户态、继续执行用户程序。

4. 中断与异常

题目:比较中断和异常的区别,并举例说明它们的应用场景。

异常处理

解题思路:

从发生时机、是否可屏蔽、来源和处理方式四个维度对照两者,再各举三个典型场景。

详细步骤:

特征中断异常
发生时机异步同步
可屏蔽性可屏蔽不可屏蔽
来源硬件设备程序执行
处理方式中断服务程序异常处理程序
优先级有优先级无优先级

中断应用场景:

  • 时钟中断:用于时间片轮转
  • I/O 中断:表示 I/O 操作完成
  • 硬件故障中断:处理硬件错误

异常应用场景:

  • 页错误:访问不存在的内存页
  • 除零错误:除数为零的除法运算
  • 非法指令:执行不存在的指令

最终答案:

中断异步发生、可屏蔽,来源是硬件设备,由中断服务程序处理;异常同步发生、不可屏蔽,来源是程序执行本身,由异常处理程序处理。中断的典型场景是时钟中断(驱动时间片轮转)、I/O 中断(表示 I/O 操作完成)和硬件故障中断;异常的典型场景是页错误、除零错误和非法指令。

5. 系统调用

题目:什么是系统调用?请举例说明常见的系统调用类型。

内存管理

解题思路:

先界定系统调用的本质——用户程序请求内核服务的接口,再按功能把常见调用分门别类。

详细步骤:

系统调用是操作系统提供给应用程序的接口,允许用户程序请求操作系统内核的服务。

常见类型:

  1. 进程管理:

    • fork():创建子进程
    • execve():执行程序
    • wait():等待子进程
    • exit():终止进程
  2. 文件操作:

    • open():打开文件
    • close():关闭文件
    • read():读取文件
    • write():写入文件
  3. 内存管理:

    • brk():调整数据段大小
    • mmap():内存映射
    • mprotect():设置内存保护
  4. 进程间通信:

    • pipe():创建管道
    • kill():发送信号
    • shmget():创建共享内存

最终答案:

系统调用是操作系统提供给应用程序、允许用户程序请求操作系统内核服务的接口。常见类型有四类:进程管理(fork() 创建子进程、execve() 执行程序、wait() 等待子进程、exit() 终止进程)、文件操作(open()、close()、read()、write())、内存管理(brk() 调整数据段大小、mmap() 内存映射、mprotect() 设置内存保护)和进程间通信(pipe() 创建管道、kill() 发送信号、shmget() 创建共享内存)。

体系结构练习题

6. 操作系统架构比较

题目:比较单内核结构和微内核结构的优缺点,并说明它们的适用场景。

操作系统架构

解题思路:

从性能、可靠性、可维护性、可扩展性四个维度对照两种结构,再各自落到适用场景上——通用系统与实时嵌入式系统的取舍正好相反。

详细步骤:

单内核结构:

优点:

  • 高性能:无进程间通信开销
  • 简单性:架构简单,易于理解
  • 效率高:内存访问效率高,系统调用开销小

缺点:

  • 可靠性问题:一个模块错误可能导致整个系统崩溃
  • 可维护性差:模块间耦合度高
  • 可扩展性有限:难以添加新功能

适用场景:通用操作系统,如 Linux

微内核结构:

优点:

  • 高可靠性:服务隔离,故障不影响整个系统
  • 可扩展性:易于添加新服务
  • 可维护性:模块独立,易于调试

缺点:

  • 性能开销:进程间通信开销,上下文切换频繁
  • 复杂性:消息传递机制复杂
  • 兼容性:与现有软件兼容性差

适用场景:实时系统、嵌入式系统,如 QNX

最终答案:

单内核结构高性能(无进程间通信开销、系统调用开销小)、简单易理解、内存访问效率高,但一个模块出错可能导致整个系统崩溃、模块耦合高、可扩展性有限,适用于通用操作系统如 Linux;微内核结构服务隔离带来高可靠性、可扩展与易调试,但进程间通信与上下文切换带来性能开销、消息传递机制复杂、与现有软件兼容性较差,适用于实时与嵌入式系统如 QNX。

7. 架构选择

题目:在设计一个实时嵌入式操作系统时,应该选择哪种架构?为什么?

架构选型

解题思路:

先从实时嵌入式系统的约束条件出发——高可靠、响应可预测、资源受限、安全敏感——再逐条对照微内核在这些维度上的优势。

详细步骤:

应该选择微内核架构,原因如下:

  1. 高可靠性:

    • 实时系统对可靠性要求极高
    • 微内核的服务隔离可以防止单个服务故障影响整个系统
    • 便于故障恢复
  2. 实时性:

    • 微内核的模块化设计便于实现实时调度
    • 可以针对实时任务优化特定服务
    • 响应时间可预测
  3. 资源效率:

    • 微内核可以根据需要加载必要的服务
    • 减少内存占用
    • 适合资源受限的嵌入式环境
  4. 可扩展性:

    • 可以根据具体应用需求添加或删除服务
    • 支持动态加载
    • 便于定制化
  5. 安全性:

    • 服务隔离提供了更好的安全性
    • 可以实施细粒度的权限控制
    • 适合安全敏感的应用

最终答案:

应选微内核架构。它在五个方面契合实时嵌入式场景:高可靠性(服务隔离,单个服务故障不影响整个系统,便于故障恢复)、实时性(模块化便于实现实时调度,可针对实时任务优化,响应时间可预测)、资源效率(按需加载必要服务、减少内存占用,适合资源受限的嵌入式环境)、可扩展性(可按需增删服务、支持动态加载、便于定制)、安全性(服务隔离支持细粒度权限控制,适合安全敏感应用)。

综合应用题

8. 系统调用实现

题目:描述一个典型的系统调用实现过程,从用户程序调用到内核服务执行再到返回用户程序。

系统调用

解题思路:

按时间顺序讲:用户态准备参数与调用号 → 触发陷入切换到内核态 → 内核定位并执行服务 → 返回值回填 → 切回用户态。

详细步骤:

系统调用实现过程:

  1. 参数准备:

    • 用户程序准备系统调用参数
    • 将参数放入寄存器或栈中
    • 将系统调用号放入指定寄存器
  2. 调用接口:

    • 通过系统调用接口进入内核
    • 触发从用户态到内核态的切换
    • 保存用户态寄存器状态
  3. 模式切换:

    • 切换到内核栈
    • 设置内核态标志
    • 跳转到内核代码
  4. 服务执行:

    • 内核验证参数的有效性
    • 检查用户权限
    • 执行相应的内核服务
    • 处理可能的错误
  5. 结果返回:

    • 将结果放入指定寄存器
    • 设置返回状态
    • 准备返回用户态
  6. 模式恢复:

    • 恢复用户态寄存器状态
    • 切换到用户栈
    • 清除内核态标志
    • 跳转到用户代码

示例(Linux read 系统调用):

// 用户程序
ssize_t read(int fd, void *buf, size_t count) {
    return syscall(SYS_read, fd, buf, count);
}

// 内核处理
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) {
    struct file *file;
    ssize_t ret = -EBADF;

    file = fget(fd);
    if (file) {
        ret = vfs_read(file, buf, count, &file->f_pos);
        fput(file);
    }
    return ret;
}

最终答案:

典型过程是:用户程序把参数放入寄存器或栈、把系统调用号放入指定寄存器;经系统调用接口触发陷入,保存用户态上下文并切换到内核态;内核根据系统调用号分发到对应处理函数(如 SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) 定义的 read 实现,完成服务并把返回值写回寄存器);最后恢复用户态上下文、切回用户态,程序从调用点继续执行。

9. 中断处理机制

题目:详细描述中断处理的过程,包括中断检测、现场保存、中断服务程序执行和现场恢复。

中断机制

解题思路:

把中断处理拆成六个阶段串起来:检测与判源 → 现场保存 → 模式切换 → 服务程序执行 → 现场恢复 → 返回被中断的程序。

详细步骤:

中断处理过程:

  1. 中断检测:

    • CPU 检测到中断信号
    • 确定中断源和中断类型
    • 检查中断是否被屏蔽
  2. 现场保存:

    • 保存当前程序计数器(PC)
    • 保存程序状态寄存器(PSR)
    • 保存通用寄存器内容
    • 保存其他相关状态信息
  3. 模式切换:

    • 切换到内核态
    • 切换到内核栈
    • 设置中断处理标志
  4. 中断服务程序执行:

    • 根据中断号查找中断服务程序
    • 执行相应的中断处理代码
    • 处理中断相关的任务
    • 清除中断标志
  5. 现场恢复:

    • 恢复通用寄存器内容
    • 恢复程序状态寄存器
    • 恢复程序计数器
    • 清除中断处理标志
  6. 程序返回:

    • 切换到用户态
    • 继续执行被中断的程序

最终答案:

中断处理流程为:① CPU 检测到中断信号,确定中断源与中断类型并检查是否被屏蔽;② 保存现场(PC、PSR、通用寄存器等);③ 切换到内核态与内核栈并设置中断处理标志;④ 按中断号查找并执行中断服务程序,处理完毕后清除中断标志;⑤ 恢复现场(通用寄存器、PSR、PC)并清除中断处理标志;⑥ 切回用户态,继续执行被中断的程序。

示例(时钟中断处理):

// 时钟中断服务程序
void timer_interrupt_handler(void) {
    // 更新系统时间
    update_system_time();

    // 检查时间片是否用完
    if (current_process->time_slice <= 0) {
        // 调度下一个进程
        schedule();
    }

    // 清除中断标志
    clear_timer_interrupt();
}

10. 架构设计决策

题目:假设你要设计一个用于智能手机的操作系统,请分析应该选择哪种架构,并说明理由。

参考答案:

应该选择混合架构,结合微内核和模块化设计的优点,理由如下:

1. 微内核基础:

  • 高可靠性:智能手机需要长时间稳定运行
  • 安全性:服务隔离可以防止恶意软件攻击
  • 模块化:可以根据需要加载不同的服务

2. 模块化设计:

  • 可扩展性:可以动态加载新的功能模块
  • 定制化:不同厂商可以定制不同的功能
  • 维护性:模块独立,便于维护和升级

3. 性能优化:

  • 关键服务优化:将性能关键的服务放在内核中
  • 缓存机制:减少进程间通信开销
  • 硬件加速:充分利用硬件特性

4. 用户体验:

  • 快速启动:只加载必要的服务
  • 流畅运行:优化调度和内存管理
  • 省电设计:根据使用情况动态调整

具体实现:

智能手机操作系统
微内核
进程管理
内存管理
进程通信
中断处理
系统服务
文件系统服务
网络服务
图形服务
音频服务
设备驱动
显示驱动
触摸驱动
摄像头驱动
传感器驱动
应用程序
系统应用
第三方应用
用户应用

这种架构既保证了系统的可靠性和安全性,又提供了良好的性能和用户体验。

发现内容有问题?

告诉我们哪里需要改进。