山东大学操作系统课程设计代码分析及设计实现及测试报告.docx
- 文档编号:9606029
- 上传时间:2023-02-05
- 格式:DOCX
- 页数:59
- 大小:51.10KB
山东大学操作系统课程设计代码分析及设计实现及测试报告.docx
《山东大学操作系统课程设计代码分析及设计实现及测试报告.docx》由会员分享,可在线阅读,更多相关《山东大学操作系统课程设计代码分析及设计实现及测试报告.docx(59页珍藏版)》请在冰豆网上搜索。
山东大学操作系统课程设计代码分析及设计实现及测试报告
操作系统课程设计报告
班级:
2012级软件工程8班
团队成员:
杨环
张俊
吴佩瑶
王飞
王梅瑞
一、前期工作
1.1平台搭建
NachosForJava
phrase1部分:
IDE环境可采用Eclipse。
Phase2及以后阶段:
需要把C程序编译成MIPS二进制文件COFF,需要MIPS的C编译器mips-x86.linux-xgcc(ubuntu12.04平台下)。
二、代码分工
三、设计及实现
3.1Task1.1KThread.join()
3.1.1要求分析
Join()方法的含义:
当前线程a在运行,执行b.join(),则a阻塞,直到线程b结束,a继续执行。
Join函数的作用即为等待某线程运行完毕。
当前线程(唯一一个正在运行的线程)A调用另一个线程(处于就绪状态)B的join函数时(A和B在Nachos中均为KThread类型对象),A被挂起,直到B运行结束后,join函数返回,A才能继续运行。
注意在一个KThread对象上只能调用一次join,且当前线程不能对自身调用join。
3.1.2设计方案
为每个线程创建一个线程队列joinqueue,joinqueue由对本线程调用join方法的其他线程对象构成,可“捐赠”优先级,以及布尔形变量joined,判断本线程是否被其他线程调用过join方法,以及一个判断线程状态方法IsAlive()。
假设当前线程A调用就绪线程B的join函数.在join函数中线程A被添加到线程B的线程队列joinqueue中,将线程A“休眠”,线程B得到执行,在线程B结束时(此时线程B成为当前线程,发生在KThead.finish函数中)选择B的joinqueue的nextThread()执行,A唤醒并继续.
3.1.3实现代码
在KThread.java中:
privateThreadQueuejoinQueue=null;
privatebooleanJoined=false;
publicbooleanIsAlive(){
if(this.status==statusNew||status==statusReady||
status==statusRunning||status==statusBlocked)
returntrue;
elsereturnfalse;
}
publicvoidjoin(){
//
if(!
this.IsAlive())return;
while(IsAlive()){
//
this.joinQueue.acquire(this);
//
}
this.joinQueue.waitForAccess(KThread.currentThread());
KThread.sleep();
//
}
}
publicstaticvoidfinish(){
///
if(currentThread.Joined){
currentThread.joinQueue.nextThread().ready();
}
///
}
3.1.4测试代码及结果
创建AThread和Bthread两个线程,AThread循环打印“AThread循环第..次”语句,Bthread开始打印“B_thread就绪”语句,中间执行AThread。
Join()方法,最后打印“B_thread执行结束”语句。
测试代码:
packagenachos.threads;
importnachos.machine.*;
publicclassKThreadTest{
publicKThreadTest(){
}
publicstaticvoidsimpleJoinTest(){
KThreadA_thread=newKThread(newKThreadTest.A_thread(5));
KThreadB_thread=newKThread(newKThreadTest.B_thread(A_thread));
B_thread.fork();
B_thread.join();
}
publicstaticclassB_threadimplementsRunnable{
B_thread(KThreadjoinee){
this.joinee=joinee;
}
publicvoidrun(){
System.out.println("B_thread就绪");
System.out.println("ForkingandjoiningA_thread...");
this.joinee.fork();
this.joinee.join();
System.out.println("B_thread执行结束");
}
privateKThreadjoinee;
}
publicstaticclassA_threadimplementsRunnable{
A_thread(intnum){
this.num=num;
}
publicvoidrun(){
System.out.println("A_thread就绪");
System.out.println("A_thread开始执行");
//Thisshouldjustkillsomecycles
for(inti=0;i System.out.println("A_thread循环第"+i+"次"); KThread.currentThread().yield(); } System.out.println("A_thread执行结束"); } privateintnum; } } 测试结果: 3.2Task1.2condition2类 3.2.1要求分析 threads.Lock类提供了锁以保证互斥.在临界代码区的两端执行Lock.acquire()和Lock.release()即可保证同时只有一个线程访问临界代码区.条件变量建立在锁之上,由threads.Condition实现,它是用来保证同步的工具.每一个条件变量拥有一个锁变量(该锁变量亦可被执行acquire和release操作,多个条件变量可共享同一个锁变量).当处于临界区内的拥有某锁Lock的当前线程对与锁Lock联系的条件变量执行sleep操作时,该线程失去锁L并被挂起.下一个等待锁L的线程获得锁L(这个过程由调度程序完成)并进入临界区.当拥有锁L的临界区内的当前线程对与锁L联系的条件变量执行wake操作时(通常调用wake之后紧接着就是Lock.release),等待在该条件变量上的至多一个被挂起的线程(由调用sleep引起)被重新唤醒并设置为就绪状态.若执行wakeall操作,则等待在该条件变量上的所有被挂起的线程都被唤醒.threads.condition已经实现了一个条件变量(采用信号量实现),题目要求用屏蔽/禁止中断的方法再实现一下条件变量(写在threads.condition2中) 3.2.2设计方案 为每个条件变量添加一个锁conditionLock和一个Kthread对象组成的等待队列waitqueue,condition.sleep将调用sleep()的线程加入到等待队列,释放锁,并阻塞,以便其他线程唤醒它,一旦’唤醒’立即要求锁,并在sleep函数开始/结尾处屏蔽/允许中断以保证原子性;condition.wake中从等待队列中取出线程进行ready()实现唤醒, (同样要在wake函数开始/结尾处屏蔽/允许中断),wakeall函数的实现依赖于wake.只需不断地wake直到队列为空为止. 3.2.3实现代码 见threads/condition2.java privateLockconditionLock; privateLinkedList publicvoidsleep(){ // waitQueue.add(KThread.currentThread()); conditionLock.release(); KThread.sleep(); conditionLock.acquire(); // } publicvoidwake(){ // waitQueue.remove().ready(); // } 3.2.4测试代码及结果 创建共有条件变量c2test,一个临界资源count和三个线程,thread1,thread2,thread3,初始化三个线程后thread1,thread2调用c2test.sleep()后开始“睡眠”,thread3调用c2test.wakeAll()唤醒所有线程,thread1,thead2开始交替访问临界资源count并更改其“余额”数值。 测试代码: packagenachos.threads; importnachos.machine.*; publicclassCondition2Test{ Lockcondlock=newLock(); Condition2c2test=newCondition2(condlock); publicCondition2Test(){ } publicvoidsimpleCondition2Test(){ System.out.println("\n****Condition2Testisnowexecuting.****"); System.out.println("初始化账户余额为10000"); finalMyCountmyCount=newMyCount("0000001",10000);//创建并发访问的账户 KThreadthread1=newKThread(newRunnable(){ publicvoidrun(){ newSaveThread("张三",myCount,2000); System.out.println("张三goestosleep"); condlock.acquire(); c2test.sleep(); System.out.println("张三reacquireslockwhenwoken."); condlock.release(); System.out.println("张三isawake! ! ! "); myCount.save(2000,"张三"); } }); KThreadthread2=newKThread(newRunnable(){ publicvoidrun(){ newSaveThread("李四",myCount,2000); System.out.println("李四goestosleep"); condlock.acquire(); c2test.sleep(); System.out.println("李四reacquireslockwhenwoken."); condlock.release(); System.out.println("李四isawake! ! ! "); myCount.save(2000,"李四"); } }); KThreadthread3=newKThread(newRunnable(){ publicvoidrun(){ System.out.println("thread3Wakingupthethread"); condlock.acquire(); c2test.wakeAll(); condlock.release(); System.out.println("张三and李四wokeupbywakeAll"); } }); thread1.fork(); thread2.fork(); thread3.fork(); thread1.join(); thread2.join(); thread3.join(); System.out.println("****Condition2Testfinished.****\n"); } } classSaveThreadextendsKThread{ privateStringname;//操作人 privateMyCountmyCount;//账户 privateintx;//存款金额 SaveThread(Stringname,MyCountmyCount,intx){ this.name=name; this.myCount=myCount; this.x=x; } publicvoidrun(){ myCount.save(x,name); } } classMyCount{ privateStringid;//账号 privateintcash;//账户余额 Locklock=newLock();//账户锁 Condition2c2test=newCondition2(lock); MyCount(Stringid,intcash){ this.id=id; this.cash=cash; } publicvoidsave(intx,Stringname){ lock.acquire();//获取锁 if(x>0){ cash+=x;//存款 System.out.println(name+"存款"+x+",当前余额为"+cash); } lock.release();//释放锁 } } 测试结果: 3.3Task1.3alram类 3.3.1要求分析 一个线程调用waitUntil(x)后,它即被挂起.在当前时钟走过x个滴答后,该线程被重新唤醒.线程被唤醒后并不一定立即进入运行态,只要将其放入就绪队列中即可.另外,多个线程可以分别调用waitUntil函数。 3.3.2设计方案 于Alarm类有关的是machine.Timer类.它在大约每500个时钟滴答使调用回调函数(由Timer.setInterruptHandler函数设置).因此,Alarm类的构造函数中首先要设置该回调函数Alarm.timerInterrupt(). 为了实现waitUntil,需要在Alarm类中实现一个队列Alarm.alarmQueue.队列中的每个项目是(线程,唤醒时间,相应条件变量)的三元组.在调用waitUntil(x)函数时,首先得到关于 以上三元组的信息: (线程: 当前线程,唤醒时间: 当前时间+x,新分配的条件变量),然后将该元组放入队列中,并对条件变量sleep操作使当前线程挂起.在时钟回调函数中(大约每500个时钟间隔调用一次)则依次检查队列中的每个三元组.如果唤醒时间大于当前时间,则将元组移出队列并对元组中的条件变量执行wake操作将相应线程唤醒. 3.3.3实现代码 publicvoidtimerInterrupt(){ // while(! alarmqueue.isEmpty()&&(alarmqueue.peek().wakeTime<=Machine.timer().getTime())){ AlarmThreadthread=alarmqueue.remove(); thread.waitThread.ready(); } // } publicvoidwaitUntil(longx){ // AlarmThreadthread=newAlarmThread(KThread.currentThread(),wakeTime,conditionlock); alarmqueue.add(thread); KThread.sleep(); // } privateKThreadwaitThread; privateConditiontimecondition; privatelongwakeTime; 3.3.4测试代码及结果 创建5个线程,依次“睡眠”20000ticks,线程醒来后各自打印出睡眠开始时间,要求睡眠时间,醒来时间,以及实际睡眠时间。 测试代码: publicstaticvoidselfTest(intnumOfTest){ Runnablea=newRunnable(){ publicvoidrun(){ AlarmTestThread(); } }; for(inti=0;i intnumOfThreads=5; print("Creating"+numOfThreads+"numofthreads"); for(intj=0;j KThreadthread=newKThread(a); thread.setName("thread"); thread.fork();} ThreadedKernel.alarm.waitUntil(30000000); } } staticvoidAlarmTestThread(){ longsleepTime=20000; longtimeBeforeSleep=Machine.timer().getTime(); ThreadedKernel.alarm.waitUntil(sleepTime); longtimeAfterSleep=Machine.timer().getTime(); longactualSleepTime=timeAfterSleep-timeBeforeSleep; print(KThread.currentThread().toString()+"被要求在: "+timeBeforeSleep+"睡眠"+sleepTime+"ticks"); print(KThread.currentThread().toString()+"被唤醒时间: "+Machine.timer().getTime()+"要求睡眠时间: : "+sleepTime+"ticks,实际睡眠时间: "+actualSleepTime); } publicstaticvoidprint(StringMessage){ System.out.println(Message); } 测试结果: 3.4Task1.4communicator类 3.4.1要求分析 用条件变量实现Communicator类中的speaker()和listen()函数一个锁lock 两个条件变量speaker(lock),listener(lockw)用来用来控制听说动作。 3.4.2设计方案 每个Communicator有一个锁lock(保证操作的原子性)和与该锁联系的两个条件变量用于保证speaker和listener间的同步.在speak函数中,首先检查若已经有一个speaker在等待(message变量)或无listener等待,则挂起.否则设置message变量,准备数据并唤醒一个listener.在listen函数中,增加一个listener后,若speaker数目非零且listener数目为1(及恰好可以配对)首先唤醒speaker,然后将自己挂起以等待speaker准备好数据再将自己唤醒.这个问题其实是一个缓冲区长度为0的生产者/消费者问题。 3.4.3实现代码 Communicator.java intspeakersize,listenersize; intMessage; Conditionspeaker,listener; publicvoidspeak(intword){ // while(speakersize! =0) {speaker.sleep();} this.Message=word; speakersize++; while(listenersize==0) {speaker.sleep();} listener.wake(); speakersize--; speaker.wake(); // } publicintlisten(){ // listenersize++; if(listenersize==1&&speakersize! =0) speaker.wake(); listener.sleep(); intmyMessage=this.Message; listenersize--; // returnmyMessage; } 3.4.4测试代码及结果 测试代码: packagenachos.threads; importnachos.machine.*; importjava.util.ArrayList; importjava.util.Random; publicclassCommunicatorTest{ publicCommunicatorTest(){ Message=1; numOfSpeakers=5; numOfListeners=5; communicator=newCommunicator(); } publicvoidcommTest(intnum){ System.out.println("\nCommunicatorTest开始");
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 山东大学 操作系统 课程设计 代码 分析 设计 实现 测试报告