Lab 5
功能实现
sys_enable_deadlock_detect
- 修改
ProcessControlBlockInner
结构体, 为mutex
和semaphore
分别实现死锁检测算法所需的数据结构. - 为
ProcessControlBlockInner
结构体实现fn deadlock_detect()
进行死锁检测. sys_thread_create()
创建新线程时, 更新allocation
与need
.sys_mutex_create()
和sys_semaphore_create()
创建资源后, 更新available
的大小, 扩展allocation
与need
.sys_mutex_lock()
和sys_semaphore_down()
申请资源时, 将need
增加, 并进行死锁检测, 通过后减少need
, 减少available
并增加allocation
以使用资源.sys_mutex_unlock()
和sys_semaphore_up()
归还资源, 将available
增加,allocation
减少以释放资源.
实验用时
- 阅读文档及代码框架: 2h.
- 功能实现与报告: 2.5h.
问答题
在我们的多线程实现中, 当主线程 (即 0 号线程) 退出时, 视为整个进程退出, 此时需要结束该进程管理的所有线程并回收其资源. 需要回收的资源有哪些? 其他线程的 TaskControlBlock 可能在哪些位置被引用, 分别是否需要回收, 为什么?
答: (1) 回收所有子线程的
TaskUserRes
, 包括用户栈, Trap 上下文以及进程pid
, 回收子进程列表以及用户空间数据. (2) 其他线程的 TaskControlBlock 可能在调度队列或等待某些同步原语时被引用, 无需回收, 会在主线程回收时一起回收.
对比以下两种
Mutex.unlock
的实现, 二者有什么区别? 这些区别可能会导致什么问题?impl Mutex for Mutex1 { fn unlock(&self) { let mut mutex_inner = self.inner.exclusive_access(); assert!(mutex_inner.locked); mutex_inner.locked = false; if let Some(waking_task) = mutex_inner.wait_queue.pop_front() { add_task(waking_task); } } } impl Mutex for Mutex2 { fn unlock(&self) { let mut mutex_inner = self.inner.exclusive_access(); assert!(mutex_inner.locked); if let Some(waking_task) = mutex_inner.wait_queue.pop_front() { add_task(waking_task); } else { mutex_inner.locked = false; } } }
答: 二者的区别在于对锁的状态修改. 第一种实现的逻辑是错误的.
第一种释放锁时, 可能会被其他线程抢占, 任务不一定持有锁; 第二种将任务加入队列时, 同时实现了锁的继承.