Pintos 实验1 Mission2记录(下)
上期说到,我们把优先级调度做好了。
现在是实现优先级捐赠。
本实验是基于和LX同学一起在5教站了一下午的基础上才写出来的,这篇报告有LX同学大于或等于于一半的功劳。
我先和LX同学一起看了各个测试点,整理思路,我这篇文章也按照这个顺序来写。
做题第一步:先遍历所有测试点
1.priority-donate-chain
2.priority-donate-lower
这个测试点主要是改变了原始线程的优先级,但是因为它还持有其他线程正在等待的锁,所以优先级不能降低,但测试点要求我们保存该设置操作,在锁释放之后要能看到影响。
3.priority-donate-multiple
这个测试点主要是用优先级为31的主线程申请了两个锁a、b,先后用优先级为32、33的线程A,线程B(大写用来区分)来申请锁a、b,导致主线程的优先级变成32,接着又变成33.
随后主线程释放b锁,此时主线程优先级应当变回32,B立即运行(优先级33比其他都高了),之后主线程运行,解锁a锁,优先级变成31,A立即运行,结束后主线程接着运行,结束。
这个测试点的主要要点在于解锁后可能需要下调优先级,并让出CPU,但不能一次性下降到最早的优先级,因为还持有其他线程正在等待的锁。
4.priority-donate-multiple2
这个和上一个测试点很接近,但主线程先释放手中的对应优先级低的线程所申请的锁,此时主线程优先级不应该改变。
5.priority-donate-nest
首先,主线程(31、low priority)初始化两个锁a、b,并持有b,然后创建一个medium线程(32)持有b锁,申请a锁,那么主线程优先级变成32,再创建一个high线程(33)申请b锁,此时medium优先级捐赠应该变成33
,递归地:主线程优先级应该也变成33.随后释放a锁,medium获得a锁运行,接着释放a,然后释放b,此时high抢占CPU,运行结束,medium结束,low结束。
这个测试点的要点还是在于优先级的捐赠与递归
6.priority-donate-one
(simple routine doesn't deserve my effort.jpg)
就是主线程(31)分别创建两个线程(32、33)申请主线程持有的锁,于是主线程的优先级变成32、33。主线程释放锁之后,33那个线程先运行结束,然后32,然后主线程。
7.priority-donate-sema
在这个测试点中,主线程先创建了一个lock和一个信号量sema,它先创建一个low(32),拿到锁,申请信号量,但是此时信号量为0,low被阻塞。
主线程再创建一个med(34)申请lock,但锁已经被占有了,low优先级变成34。加入某个时间点med拿到锁,它还会执行sema_down
最后主线程创建了一个high线程(36)申请锁,如果它拿到了锁,他会执行sema_up。
这个测试点的要点在于,当主线程sema_up之后,low运行,释放锁,此时必须由优先级较高的high拿到锁,否则med会请求sema_down,最终死锁。
实现思路
测试点看完了,开始整理思路,先从priority-donate-one开始,最基本的就是当申请锁时,要判断现在锁是否被持有,如果没有,那拿着就行,否则要把优先级传递给现在的持有者。
但是priority-donate-chain告诉我们,这个持有者有可能也正在等待其他的线程持有的锁,所以需要实现递归捐赠。
首先我们利用锁数据结构里的holder,在某一个线程申请锁且发现锁被占有的时候,判断这个holder的优先级是不是比自己的低,如果是就要捐赠,并且递归地区看这个holder有无在等待的锁,所以我们在struct thread这一个数据结构里还要加一个变量waiting_lock,用来存正在等待的锁,这样就可以构成一个链表递归调用了。
thread里面增加一个 struct lock* waiting_lock。
thread的初始化要加上我们新增的三个变量
lock_acquire函数
优先级的递归捐赠
释放锁以及thread_set_priority的时候,要考虑到目前的这个线程是不是还持有别人正在等待的锁,优先级不能随便降低;但是与此同时thread_set_priority函数必须起作用,不能被“吞掉”,那么我们将它起的作用保存起来,作为实际的优先级old_priority,如果在释放锁的时候还要遍历自己持有的其他锁,观察其每一个的优先级最高的等待者的优先级,和old_priority结合起来取最大值作为表现出来的priority,也就是数据结构里面的priority。
thread数据结构在前面已经提到了。主要post一下thread_set_priority和lock_release。
thread_set_priority函数
lock_release函数
priority-donate-sema告诉我们,在两个优先级不一样的线程等待同一个锁的时候,要由优先级高的获得,这个我们只要在把当前线程插入到lock里的sema的waiter队列里的时候按顺序插入即可,这个对sema_down的修改在改为优先级调度时就已经做过了。