问题描述
- Note that another thread does not have to call join(), but if it is called, it must be called only once.
- A thread must finish executing normally whether or not it is joined.
问题思考
#
1.KThread.join函数如果被调用也只能被调用一次,第二次调用的结果是未知的。
2.每个线程都维护自己的资源,(在Linux和Windows操作系统中,线程维护的资源存在于TCB中)换言之,每个线程拥有自己的waitJoinQueue,里面存放了由于自己的join而被阻塞无法执行的线程。
3.由于我们对每个线程添加了waitJoinQueue切里面存有在等待的线程,故而我们需要修改finish函数,在线程完成运行即将终止时检查其waitJoinQueue,唤醒队列中在等待的线程。
解决方案
(1)Kthread的join()中的Lib.assertTrue(this != currentThread)已经实现线程只能调用一次join()方法,根据要求,在调用join()方法时,让当前运行线程休眠,并将当前运行的线程加入到一个阻塞队列中。
(2)在线程结束时,finish()函数循环唤醒所有被阻塞的线程。Finish()函数在run()函数返回时自动调用,同样可以被直接调用。但当前唯一运行的线程不能被finish()函数立即结束,只有当其他线程运行时才可结束。
线程状态转换图
实现代码
public void join() {
Lib.debug(dbgThread, "Joining to thread: " + toString());
Lib.assertTrue(this != currentThread);
//工作
/*if(!this.IsAlive()) return;
while(this.IsAlive())
{
this.joinQueue.acquire(this);
}
this.joinQueue.waitForAccess(KThread.currentThread());
KThread.sleep();//当前进程等待被调用的进程结束。*/
/**for join method**/
boolean intStatus = Machine.interrupt().disable(); //系统关中断
if (status != statusFinished)
{
waitJoinQueue.waitForAccess(currentThread); //调用另一个要调用的进程
KThread.sleep(); //当前进程睡眠等待被调用进程结束
}
Machine.interrupt().enable();
/**for join method**/
}
public static void finish() {
Lib.debug(dbgThread, "Finishing thread: " + currentThread.toString());
Machine.interrupt().disable();//关中断
Machine.autoGrader().finishingCurrentThread();
Lib.assertTrue(toBeDestroyed == null);
toBeDestroyed = currentThread;//表明进程要结束了
currentThread.status = statusFinished;//当前进程状态修改为运行结束。
//工作开始
KThread waitThread= currentThread.waitJoinQueue.nextThread(); //调用等待队列上的第一个进程; //调用等待队列上的第一个进程
while (waitThread != null) //while
{
waitThread.ready(); //唤醒等待队列上所有被阻塞的进程
waitThread= currentThread.waitJoinQueue.nextThread(); //调用等待队列上的第一个进程
}
sleep();
//工作结束:
//sleep();
}
测试代码及结果
结果
这里只测试了Test1
方法,
可以看到,实现了join方法。至此,pro1.1
就
已经全部实现了。
需要注意的几个地方
1.join:Kthread的join()中的Lib.assertTrue(this != currentThread)已经实现线程只能调用一次join()方法。还有finish函数的调用:Finish()函数在run()函数返回时自动调用,同样可以被直接调用。但当前唯一运行的线程不能被finish()函数立即结束,finish函数的测试也花费了一些时间。
waitJoinQueue的初始化要求在每个线程中都得到执行,不然会爆空指针异常,后来发现是finish的if 和while循环的差别。
2.Joincounter静态全局变量记录join方法被调用的次数以控制其满足题目要求
3.一定要记得修改finish方法唤醒waitJoinQueue中等待的线程