嵌入式操作系统面试高频考点解析
1. 进程与线程
1.1 基本概念差异
- 进程:操作系统资源分配的最小单位,拥有独立的地址空间
- 线程:CPU调度的基本单位,共享进程地址空间但拥有独立堆栈和局部变量
1.2 关键特性对比
| 特性 | 进程 | 线程 |
|---|
| 地址空间 | 独立 | 共享 |
| 健壮性 | 一个进程崩溃不影响其他 | 线程崩溃可能影响同进程其他线程 |
| 创建开销 | 较大 | 较小 |
| 上下文切换开销 | 较大 | 较小 |
2. 进程间通信机制
2.1 管道通信
// 无名管道创建示例 int pipe(int pipefd[2]);
- 无名管道:仅限亲缘关系进程间通信,单向字节流
- 有名管道(FIFO):突破亲缘限制,通过文件系统路径访问
2.2 其他通信方式
- 消息队列:数据块传输,需用户/内核空间拷贝
- 共享内存:最高效但需处理资源竞争
- 信号:异步事件通知机制
- 信号量:同步互斥控制
- Socket:跨主机通信解决方案
3. 进程调度算法
3.1 基础算法
- FCFS:先到先服务,简单但平均等待时间长
- SJF:最短作业优先,理论上最优但需预知运行时间
- 优先级调度:可能产生饥饿现象
3.2 高级算法
- 时间片轮转:公平但上下文切换开销大
- 多级反馈队列:
- 多级队列,优先级递减
- 时间片递增
- 新进程进入最高优先级队列
4. 特殊进程类型
4.1 孤儿进程
- 产生条件:父进程先于子进程终止
- 处理机制:被init进程(pid=1)收养
- 资源回收:由init进程负责wait
5. 线程同步机制
5.1 同步原语对比
| 机制 | 适用场景 | 特点 |
|---|
| 互斥量 | 临界区保护 | 简单高效 |
| 读写锁 | 读多写少 | 允许并发读 |
| 条件变量 | 事件等待 | 需与互斥量配合使用 |
| 信号量 | 资源计数 | 可跨进程 |
| 自旋锁 | 短临界区 | 忙等待不释放CPU |
6. 进程内存布局
6.1 Linux进程地址空间
- 内核空间:运行操作系统核心代码
- 栈区:自动管理,存放局部变量和函数调用信息
- 堆区:动态内存分配区域
- 数据段:
- .bss:未初始化全局变量
- .data:已初始化全局变量
- 代码段:只读的程序指令
7. 内存管理问题
7.1 内存碎片类型
- 外部碎片:空闲内存总量足够但无法满足连续分配
- 内部碎片:分配单元未使用部分
7.2 解决方案
- 内存池技术
- slab分配器
- 紧凑(compaction)技术
8. 堆栈对比分析
8.1 核心差异
| 特性 | 栈 | 堆 |
|---|
| 管理方式 | 编译器自动分配释放 | 程序员手动控制 |
| 分配效率 | 高(指针移动即可) | 低(需查找合适内存块) |
| 容量限制 | 较小(通常MB级) | 较大(受虚拟内存限制) |
| 碎片问题 | 无 | 存在外部和内部碎片 |
9. 同步原语深入
9.1 互斥锁vs信号量
- 互斥锁:二元状态,严格互斥访问
- 信号量:计数机制,可实现复杂同步模式
9.2 使用注意事项
- 避免锁嵌套导致的死锁
- 注意锁粒度对性能的影响
- 优先使用读写锁优化读多写少场景
10. 同步与异步
10.1 执行流程差异
// 同步调用示例 result = sync_call(); // 异步调用示例 async_call(callback);
10.2 适用场景
- 同步:流程严格依赖调用结果
- 异步:提高系统吞吐量,避免阻塞
11. 死锁问题
11.1 必要条件
- 互斥访问
- 占有并等待
- 不可抢占
- 循环等待
11.2 解决方案
- 预防:破坏任一必要条件
- 检测与恢复:定期检测死锁并采取措施
11.3 实际工程建议