本课程通过设计和实现线程调度算法来探索操作系统的内部机制,旨在加深学生对多任务处理和资源管理的理解。
### 操作系统实验——线程的调度
#### 实验背景及目标
本次实验旨在通过实践操作使学生深入了解操作系统中的线程调度机制,特别是优先级调度策略。通过一系列步骤,包括修改现有代码来实现静态与动态优先级,并基于此设计并实现一种简单的优先级调度算法。完成实验后,学生应掌握以下知识点:
1. **线程优先级的基本概念**:了解线程优先级的概念及其分类。
2. **静态优先级与动态优先级的区别**:理解两种优先级的不同之处以及它们是如何影响线程调度的。
3. **优先级调度算法的设计与实现**:学会如何设计并实现一个简单的优先级调度算法。
#### 实验内容详解
1. **静态优先级 (nice)**:
静态优先级是指为线程设置的一个初始值,通常不会因为时间或行为改变。通过特定的系统调用如 `setpriority` 进行手动调整。实验中实现步骤包括:
- 在 `struct tcb` 结构体添加成员变量 `nice` 表示静态优先级。
- 初始化新线程时默认设置为0。
- 提供系统调用 `sys_getpriority` 和 `sys_setpriority` 来获取和修改静态优先级。
2. **动态优先级 (priority)**:
动态优先级是基于使用情况(如CPU时间)自动计算的。实现步骤包括:
- 在 `struct tcb` 结构体增加成员变量 `estcpu` 和 `priority`。
- `estcpu` 记录线程最近使用的CPU时间量,`priority` 通过公式计算得出:优先级 = PRI_USER_MAX - (estcpu / 4) - (nice * 2),其中PRI_USER_MAX是最高用户线程优先级。
- 动态优先级需要考虑系统平均负荷。引入全局变量 `g_load_avg` 跟踪。
3. **全局变量 `g_load_avg`**:
这个变量存储系统的平均负载,影响动态优先级计算:
- 在定时器中断处理程序中更新。
- 每秒根据公式 g_load_avg = (59/60) * g_load_avg + (1/60) * nready 更新一次(nready 表示就绪线程数量)。
4. **优先级调度算法的实现**:
完成准备后,修改 `schedule` 函数以实现优先级调度:
- 在函数中计算每个线程动态优先级。
- 根据优先级选择下一个执行的线程。
- 特别注意:特殊线程task0只有在没有其他可运行时才被调度。
5. **测试与验证**:
最后一步是通过编写或使用现有测试框架来验证实现是否符合预期行为。
#### 实验环境
- 编译器:GCC
- 链接器:LD
- 调试器:GDB
- 模拟器:QEMU
#### 实验步骤总结
1. **添加静态优先级字段**:
在 `struct tcb` 中加入 `nice` 字段,并初始化。
2. **增加系统调用**:
实现 `sys_getpriority` 和 `sys_setpriority` 获取和修改线程的静态优先级。
3. **增加动态优先级相关字段**:
在结构体中添加成员变量以记录CPU使用时间(estcpu)与计算出的动态优先级(priority)。
4. **实现全局变量 g_load_avg**:
用于跟踪系统的平均负载,影响调度算法中的权重值调整。
5. **属性计算**:
定时器中断函数中更新 `g_load_avg` 和线程的 estcpu 值以反映当前系统状态。
6. **修改调度函数**:
在 schedule 函数内实现基于优先级选择下一次执行任务的功能逻辑,确保算法正确性。
7. **测试调度器**:编写脚本或使用现有框架验证实验结果是否符合预期。
通过以上步骤的学习和实践,学生不仅深入理解了线程调度机制的运作原理,并掌握了如何在实际操作系统中实现这些机制。这对未来从事相关工作的同学来说是非常宝贵的经验积累。