# 用户级线程库的实现
# 1 设计目标
本次课程设计的目标是开发一个用户级线程库,功能包括完整的线程创建/删除/joining,互斥锁,条件变量,以及一个基于优先级的调度器。完成此用户级线程库,可以使用该线程库编写多线程的应用,替代 Linux 中的 pthreads.
# 2 线程库的具体内容
使用线程库前首先要调用 uthread_init()。这个函数只执行一次,负责初始化数据结构,比如全局 uthreads 矩阵和 ut_curthr(当前正在执行的线程)。 uthread_init()中有一些特殊的代码,处理当前正在执行的进程的上下文(即调用 uthread_init()的进程),使其成为一个有效的 uthread,并设置 ut_curthr 为该 uthread,这个 uthread 被称为主线程或 0 号线程。所有事情初始化后,可以使用线程 uthread_create()创建线程。
一旦创建好线程,线程库能够调度这些线程。若线程需要暂时 yield 处理器给另一个线程 (仍然是可执行的,即处于就绪态),则需要调用 uthread_yield()。线程可以通过 uthread_block()进入睡眠态,也可以通过 uthread_wake()被唤醒。uthread_switch()函数负责选择另一个线程运行。调度器调度时,采用优先级调度算法,线程优先级可以由 uthread_setprio()设置,数字越大优先级越高,相同优先级的线程则轮流使用 CPU。每个优先级一个队列,相关的数据结构见 uthread_sched.c 中的 runq_table。
Uthreads 中的线程有 6 种状态,定义如下:
```c
typedef enum {
UT_NO_STATE, /* 无效的线程状态 */
UT_ON_CPU, /* 线程正在执行 */
UT_RUNNABLE, /* 线程可运行,就绪 */
UT_WAIT, /* 线程被阻塞 */
UT_ZOMBIE, /* 线程处于 zombie 状态,即已结束,但需要回收资源 */
UT_TRANSITION, /* 线程处于创建状态 */
UT_JOINABLE, //线程结束时需要一个线程回收其资源
UT_DETACHABLE, //线程结束时,不需要一个线程回收其资源
UT_NUM_THREAD_STATES //线程状态数目
} uthread_state_t;
```
![](https://www.writebug.com/myres/static/uploads/2021/12/15/17f091555e4c38563bc0ae3e680aafd8.writebug)
在 uthreads 中永远不会有多于一个线程同时执行,但线程可被抢占。在 uthreads 中,使用 uthread_makecontext()创建线程的机器上下文。如果需要改变当前正在执行线程,需要调用 uthread_swapcontext(),这使得当前 CPU 上下文被保存,新的上下文被执行。保存的上下文作为 newctx 参数在之后调用 uthread_swapcontext()时被重新执行。
Uthread 中有一个线程称之为 Reaper 线程,也就是 1 号线程,负责清理已结束线程占用的资源。值得注意的是 reaper 并不清理已经结束但还没有 joined 的 non-detached 线程,而是让 uthread_join()去完成。
# 3 实现过程
需要实现的函数如下(更具体的实现思路请看源代码的注释)。
uthread_yield:当前正在运行的线程让出 CPU,线程仍然处于可运行状态,即 UT_RUNNABLE。调用此函数时,当前线程加入到就绪队列,如果当前线程大于系统中已有的最高优先级线程,则直接从 uthread_yield 返回;否则放弃 CPU,转去执行最高优先级的线程。
uthread_wake:唤醒指定的线程,使其可再次被执行(注意:线程有可能已经处于就绪态)。所作的事情:改变状态,将其放入就绪队列。
uthread_setprio:改变指定线程的优先级。注意,如果线程已处于 UT_RUNNABLE 状态(可执行,但没有占有 CPU),则应该改变其优先级队列,如果该指定线程的优先级高于当前调用者,则调用者还要放弃 CPU;如果线程状态为 UT_TRANSITION,则它是一个刚创建的线程(即将第一次被放入就绪队列),将其状态改为 UT_RUNNABLE。成功时返回 1,否则返回 0。
![](https://www.writebug.com/myres/static/uploads/2021/12/15/af199ccdc0cbb485a8c67abd65f145f8.writebug)
uthread_switch:找到最高优先级的可运行线程,然后使用 uthread_swapcontext()切换到它(注意设置 UT_ON_CPU 线程状态和当前线程)。如果调用线程本身就是最高优先级线程,则切换回调用线程。主要工作:找出系统中优先级最高的线程,并切换(必须要有可执行线程)。
![](https://www.writebug.com/myres/static/uploads/2021/12/15/af6b98393365f49b41203785e60137bc.writebug)
uthread_init:这个函数只在用户进程启动时调用一次,用于初始化所有的全局数据结构和变量。这个函数需要设置每一个线程的 ut_state 和 ut_id,简单起见,本系统中选择线程数组的下标作为 ut_id。
uthread_create:创建一个线程执行指定的函数<func>,函数的参数为<arg1>和<arg2>,优先级为<prio>。首先,使用uthread_alloc找到一个有效的id,找不到时,返回合适的错误;然后,为线程分配栈,分配不成功时返回合适的错误;使用uthread_makecontext()创建线程的上下文;按照新发现的线程id,设置uthread_t结构,调用uthread_setprio设置线程的优先级,在<uidp>中返回线程id。不成功时返回0。
uthread_exit:结束当前的线程(注意设置 uthread_t 中的标志)。如果线程是 UT_DETACHABLE,则通过调用 make_reapable()将其放入清理线程(reaper)清理队列并唤醒清理清理线程。如果线程是 UT_JOINABLE,则唤醒等待的线程。然后调用 uthread_switch()切换线程。
![](https://www.writebug.com/myres/static/uploads/2021/12/15/f450747ef8efc1852ae4d71ba412870e.writebug)
uthread_join:等待指定的线程结束,如果线程没有结束执行,调用线程需要阻塞,直到线程结束。主要工作:如果要等待的线程还没有结束,则置线程的等待线程为当前线程,线程状态改为 UT_WAIT,切换线程;如果成功地等到了线程结束,则调用 make_reapable 唤醒清理线程 reaper 将其彻底清理。错误条件及对应的 error code 参考 pthread_join 的 manpage。
![](https://www.writebug.com/myres/static/uploads/2021/12/15/3140448b0f30ab3b8c5f7de11ce6cd01.writebug)
uthread_self:返回当前正在执行的线程的 id。
uthread_alloc:找到一个自由的 uthread_t,返回其 id(uthread_id_t)。
uthread_destroy:清理指定的线程。
uthread_cond_init:初始化指定的条件变量。
uthread_cond_wait:等待指定的条件变量。改变当前线程的状态,释放当前线程占有的锁,并将当前线程放入条件变量的等待队列中,切换线程。
uthread_cond_broadcast:唤醒等待于此条件变量的所有线程。
uthread_cond_signal:唤醒等待于此条件变量的一个线程。
uthread_mtx_init:初始化指定的 mutex。
uthread_mtx_lock:如果没有线程占有该锁,则将锁的拥有者改为当前线程,否则,当前阻塞,让出 CPU。
uthread_mtx_trylock:试图上锁 mutex,得到锁时返回 1,否则返回 0。
uthread_mtx_unlock:释放锁。如果有其他线程在等待该锁,则唤醒它。
# 4 结果分析
![](https://www.writebug.com/myres/static/uploads/2021/12/15/e9b9a4787493be802eb482a7255ab9b7.writebug)
# 5 课程设计总结
在这次课程设计的过程中,我对线程调度有了更深入的了解;通过查阅 Linux 的源码和文档以及国内外相关论坛和博客,我解决了出现的各种疑惑和不解,对操作系统的原理也有了进一步的掌握;此外,我可以更熟练地使用 GDB 进行调试,能够更高效地理解和解决程序 bug。
神仙别闹
- 粉丝: 4317
- 资源: 7532
最新资源
- 基于MPC的智能车运动预测和控制算法 Motion predication; Kinematic model 可加入求解步骤进而得到自定义成本函数的可扩展MPC控制器; 模型状态空间方程线性化和
- Comsol 模拟 仿真 模型 热-流-固四场耦合增透瓦斯抽采,包括动态渗透率、孔隙率变化模型,涉及pde模块等四个物理场
- 电热冷综合能源优化调度 Matlab+Yalmip+Cplex 设备模型:风电、光电、电网交互、燃气轮机、余热锅炉、燃气锅炉、吸收式制冷剂、电制冷机、储电系统、储热系统 目标函数以成本最低进行求解
- 市面上比较流行的php客服源码,亲测可用
- Boost单闭环仿真模型,含目标输出电压阶跃变化和负载突变两种情况,闭环控制效果稳定
- 51单片机正反转可控的直流电机设计 C程序、proteus仿真、报告 支持按键设置直流电机的正转、反转、急停
- 四轮独立驱动横摆角速度控制,LQR 基于LQR算法的 基于二自由度动力学方程,通过主动转向afs和直接横摆力矩dyc实现的横摆角速度跟踪 ,模型包括期望横摆角速度,质心侧偏角,稳定性因素,lqr模块等
- 交错并联boost pfc仿真模型,采用单周期控制 输出电压,电感电流波形良好 运行环境为matlab simulink
- linux服务器实现简单实现
- 2KW光伏并网逆变器 (以下简称逆变器)总体方案包括DC AC逆变电路部分、相应的控制电路部分和显示界面 逆变器主要功能是将光伏电池组件发出的直流功率转化成交流功率,并输送到电网上 1. 功能
- 基于nmpc的路径避障跟踪控制算法,考虑原有势场避障功能函数局限性(图1),采用更好描述车辆碰撞情况的新型功能函数,作为非线性优化路径规划方法(图2),采用nmpc作为底层控制,实现仿真改变任一起始位
- 树莓派安装codesys
- 燃料电池发电系统SOFC-MFPC控制的simulink MATLAB仿真模型,附相关文献 都是平时的积累
- fpga MIL-STD1553B源码,支持BC ,BM,RT 可任意移植到xilinx,altera,actel全系列型号 功能和接口可参考actel芯片1553b核,纯源码
- 基于非对称纳什谈判的多微网电能共享运行优化策略 关键词:纳什谈判 合作博弈 微网 电转气-碳捕集 P2P电能交易交易 参考文档:《基于非对称纳什谈判的多微网电能共享运行优化策略》完美复现
- 冷热电气多能互补的微能源网鲁棒优化调度 本程序参考文章《冷热电气多能互补的微能源网鲁棒优化调度》-邹云阳的模型,但是并未实现鲁棒部分功能,整体程序实现了基本的冷热电气多能互补微网的优化调度,两个主程序
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈