操作系统nachos课程设计实验报告.docx
- 文档编号:12749912
- 上传时间:2023-04-21
- 格式:DOCX
- 页数:28
- 大小:61.96KB
操作系统nachos课程设计实验报告.docx
《操作系统nachos课程设计实验报告.docx》由会员分享,可在线阅读,更多相关《操作系统nachos课程设计实验报告.docx(28页珍藏版)》请在冰豆网上搜索。
操作系统nachos课程设计实验报告
1题目
project1:
实现nachos操作系统的project1中的join()方法,condition2类,Alarm类,Communicator类,PriorityScheduler类和Boat类
project2:
实现nachos操作系统的project2中的creatopenreadwritecloseunlink文件系统调用,修改UserProcess.readVirtualMemory和UserProcess.writeVirtualMemory使操作系统能够运行多用户程序,实现execjoinexit系统调用,实现LotteryScheduler类
2实验目的
熟悉nachos操作系统,深入理解操作系统内核了解用户程序的加载过程以及多用户进程的内存分配机制
3实验要求
完成nachos,提交设计文档和你的代码
4实验说明,程序代码及测试结果
Project1:
1join()
要求实现join()方法,注意,其他线程没必要调用join函数,但是如果它被调用的话,也只能被调用一次。
join()方法第二次调用的结果是不被定义的,即使第二次调用的线程和第一次调用的线程是不同的。
无论有没有被join,一个进程都能够正常结束
(a)设计思想
当线程B执行A.join()时,将B放入A的等待队列,直到A完成时,唤醒在等待队列中的所有线程,因此需要实现join()方法和修改finish方法(b)源代码
publicvoidjoin(){
Lib.debug(dbgThread,"Joiningtothread:
"+toString());
Lib.assertTrue(this!
=currentThread);
Lib.assertTrue(join_counter==0);
join_counter++;
booleanstatus=Machine.interrupt().disable();
if(this.status!
=statusFinished){
waitQueue.waitForAccess(KThread.currentThread());currentThread.sleep();
}
Machine.interrupt().restore(status);
}
publicstaticvoidfinish(){
Lib.debug(dbgThread,"Finishingthread:
"+currentThread.toString());
Machine.interrupt().disable();
Machine.autoGrader().finishingCurrentThread();
Lib.assertTrue(toBeDestroyed==null);toBeDestroyed=currentThread;currentThread.status=statusFinished;
KThreadthread=currentThread().waitQueue.nextThread();if(thread!
=null)
{
thread.ready();
}
sleep();
}
(c)程序截图
线程1每次执行打出执行的次数,每次执行过后放弃cpu,线程2打出
successfu,l线程2执行thread1.join().通过截图可以看出代码正确
2Condition2
通过使用开关中断提供原子性来直接实现条件变量,我们利用信号量提供了一个简单的实现方式,你的工作就是不直接使用信号量提供相同的实现(你或许使用锁,即使它们也间接的使用了信号量)。
一旦你实现了,你将会有两种可选
择的实现方式来提供相同的功能。
你的第二种条件变量的实现必须放在
Condition2中
(a)设计思想
Condition2是对使用该条件变量的线程进行管理,所以要把在这个条件变量上等待的进程储存起来,因此可以使用一个队列。
sleep()方法是把等待该条件变量的线程阻塞,放入等待队列,直到执行了wake()并且获得cpu才能继续执行,执行步骤:
关中断,释放锁,把线程放入等待队列,获得锁,开中断。
wake()方法是把条件变量中的线程移出,放入就绪队列。
执行步骤:
关中断,线程移出等待队列移入就绪队列,开中断
wakeAll()方法是将条件变量中的所有线程移出,移入就绪队列
(b)源代码
publicvoidsleep(){
Lib.assertTrue(conditionLock.isHeldByCurrentThread());
booleanstatus=Machine.interrupt().disable();
conditionLock.release();
waitqueue.waitForAccess(KThread.currentThread());
KThread.currentThread().sleep();
conditionLock.acquire();
Machine.interrupt().restore(status);
}
publicvoidwake(){
Lib.assertTrue(conditionLock.isHeldByCurrentThread());
booleanstatus=Machine.interrupt().disable();
KThreadthread=waitqueue.nextThread();
if(!
(thread==null))
thread.ready();
Machine.interrupt().restore(status);
}
publicvoidwakeAll(){
status=Machine.interrupt().disable();thread=waitqueue.nextThread();
while(!
(thread==null))
{thread.ready();
thread=waitqueue.nextThread();
}
Machine.interrupt().restore(status);
}c)程序截图
线程1线程2分别请求锁和条件变量,然后释放锁和条件变量,图中可以看出代码正确
3Alarm类
实现Alarm类,线程调用waitUntil方法之后会终止,直到传入的时间之后才
可以执行。
线程没必要在等待的时间之后立刻执行,只是把它放入ready队列,
等待分配cpu。
可以使用一个线程队列,但是不能产生额外的线程。
(a)设计思想
waitUntil()方法使用了一个队列可以存放线程以及唤醒时间,这个队列以时间为序的有序队列。
每次调用时,把当前线程和唤醒时间加入队列,等待唤醒。
timerInterrupt()方法在每一次timer产生时间中断时遍历队列,检查队列中的时间状态,当线程到了等待的时间就把线程从队列中取出放入就绪队列。
KThreadWakeTime类是一个内部类用于联系线程和唤醒时间
(b)源代码
publicvoidwaitUntil(longx){
booleanstatus=Machine.interrupt().disable();
longwaketime=Machine.timer().getTime()+x;
KThreadWakeTimekthreadwaketime=newKThreadWakeTime(
KThread.currentThread(),waketime);
intsize=linkedlist.size();
if(size==0)
linkedlist.add(kthreadwaketime);
else
for(inti=0;i if(waketime } if(i==size-1 &&waketime>=linkedlist.get(i).getWakeTime())linkedlist.add(i+1,kthreadwaketime); } KThread.currentThread().sleep();Machine.interrupt().restore(status); } publicvoidtimerInterrupt(){ booleanstatus=Machine.interrupt().disable(); longcurrenttime=Machine.timer().getTime(); intsize=if(size== linkedlist 0) .size(); else for(int i=0;i if( currenttime else{ KThreadthread=linkedlist.get(i).getThread();thread.ready(); linkedlist.remove(i); size--; i=0; currenttime=Machine.timer().getTime(); } } KThread.currentThread().yield(); Machine.interrupt().restore(status); } publicclassKThreadWakeTime{privateKThreadthread=null;privatelongwaketime=0; publicKThreadWakeTime(KThreadthread,longwaketime){this.thread=thread;this.waketime=waketime; } publicKThreadgetThread(){ returnthread; } publiclonggetWakeTime(){returnwaketime; c)程序截图 创建一个线程在70时中止,等待500后唤醒。 图中可以看出代码正确 4Communicator利用条件变量编写发送和接收一个消息来实现Communicator类的spea(k)和listen()方法。 speak()要自动等待listen()被调用,然后将消息传递给listen()。 同样的listen()也要自动等待speak()被调用,将消息传递给自己才能收到一个消息。 只有消息从speak()传递到了listen()两个线程才能返回。 在只有一个Communicator对象时也能工作起来,不能拥有缓冲区,也就是说listen()和speak()只有成功配对之后才能传递消息。 (a)设计思想speak(): 先获得锁,然后进行判断,如果没有听者等待,就要把说者放入队列然后睡眠。 如果有听者等待,就要唤醒一个听者,然后传递消息,最后释放锁。 listen(): 先获得锁,然后进行判断,如果没有说者等待,就要把听者放入队列然后睡眠。 如果有说者等待,就要唤醒一个说者,然后传递消息,最后释放锁。 (b) publicCommunicator(){ lock=newLock(); queue=newLinkedList speaker=newCondition2(lock); listener=newCondition2(lock); word=0; speakercount=0;listenercount=0; } publicvoidspeak(intword){ booleanintStatus=Machine.interruptlock.acquire(); if(listenercount==0) {speakercount++;queue.offer(word);speaker.sleep();listener.wake();speakercount--; }else {queue.offer(word);listener.wake(); }lock.release(); Machine.interrupt().restore(intStatusreturn; } publicintlisten(){booleanintStatus=Machine.interruptlock.acquire(); if(speakercount! =0){speaker.wake(); listener.sleep(); }else{listenercount++; listener.sleep();listenercount--; }lock.release(); Machine.interrupt().restore(intStatusreturnqueue.poll(); }c)程序截图 ().disable(); ); ().disable(); ); 线程1和线程2分别调用speak()将20,30传递,线程3和线程4调用listen()将消息接收。 线程1和线程2执行时没有听者,双双等待,证明程序在多个说者和听者时也能工作的很好 5 PriorityScheduler类 通过完成实现PriorityScheduler优先级调度策略。 所有的调度程序都是继承自Scheduler类,所以必须实现getPriority(),getEffectivePriority()和setPriority()方法。 在调度中必须选择有效优先级最长的执行,如果有效优先级相同的线程都在等待要选择等待时间最长的。 解决优先级问题的关键就是优先级反转,当一个高优先级的线程等待一个低优先级的线程时,高优先级的线程就必须把自己的有效优先级捐献给低优先级的线程,让低优先级的线程提高优先级可以尽快执行。 解决这个问题的关键就是计算有效优先级,但是计算时间不能太长,所以在改变优先级的时候在计算比较合适。 优先级在捐献之后不会丢失。 优先级可以不断传递下去。 (a)设计思想 在引入优先级的同时就需要引入一个ThreadState对象,它用来把线程和优先级绑定在一起。 而且内部还有一个队列用来记录等待它的线程。 在执行getEffectivePriority()方法时,要遍历整个队列,将等待它线程的最高有效优先级取出,和自己的优先级比较,把最大的当成自己的最高有效优先级。 而在遍历的过程中,如果线程还有等待的线程还要计算自己的有效优先级,所以这是一个递归搜索的过程。 而在队列类中最重要的就是nextThread()方法,它 返回下一个要执行的线程。 这个方法通过遍历队列,计算出所有线程的有效优先级,取出有效优先级最大的线程执行。 (b)源代码 publicintgetEffectivePriority(){ effectivepriority=-1; for(inti=0;i {if(waitQueue.waitQueue.get(i).getEffectivePriority()>effectivepriority) effectivepriority=waitQueue.waitQueue.get(i).getEffectivePriority(); } if(effectivepriority>priority) setPriority(effectivepriority); returnpriority; } publicKThreadnextThread(){ Lib.assertTrue(Machine.interrupt().disabled()); intmax=-1; index=0; ThreadStatestate=null,temp=null; while((temp=pickNextThread())! =null) {if(temp.getEffectivePriority()>max) {state=temp; max=temp.getEffectivePriority();} } if(state==null) {returnnull;} else {returnwaitQueue.remove(waitQueue.indexOf(state)).thread;}} protectedThreadStatepickNextThread(){ if(index {index++; returnwaitQueue.get(index-1);} returnnull; } (c)程序截图 创建三个线程thread1,thread2,thread3,分别赋予优先级为2,4,6,thread3中调用了thread1.join()。 运行之后,thread1得到了thread3的优先级,有效优先级最高,最先执行,当thread1执行完成之后,thread3的优先级最高,第二执行,thread2优先级最低最后执行。 6Boat 使用条件变量解决过河问题。 O岛有一群人要到M岛去,但是只有一艘船,这艘船一次只能带一个大人或者两个孩子。 开始必须假设至少有两个孩子(否则问题无法解决),每一个人都会划船。 要为每个大人和孩子创建一个线程,这个线程就相当于一个人,他们能自己判断(思考),什么时候可以过河,而不是通过调度程序的调度。 在解决问题的过程中不能出现忙等待,而且问题最终一定要解决。 不符合逻辑的事情不能发生,比如在这个岛的人能知道对面岛的情况。 (a)设计思想创建两种类型的线程大人线程和孩子线程,他们分别执行不同的行为。 船设置成为条件变量,人的位置,该大人还是孩子走,船是否在一个岛上设置成为布尔变量,将问题建模为数学问题。 大人进程: 首先要获得锁,然后进行判断是否是大人要走,船是否在这个岛上,如果不成立大人就要等待直到成立然后大人过河,改变变量的值,到达对岸之后唤醒一个孩子把穿开回来孩子进程: 首先要获得锁,首先判断是在哪个岛上;若在O岛,则判断运输过程是否已经结束,要是结束就不执行任何操作,要是没结束,判断是否是孩子走,船是否在这个岛上,如果不成立,孩子就要等待直到成立,两个孩子过河,改变变量的值,并且还要把是否结束的信息传递过来。 如果结束不做任何操作,否则唤醒一个孩子进程把船开回去;若在M岛,则孩子直接过河,并且根据获得信息要求下一次是大人还是孩子过河。 (b)源代码 publicstaticvoidbegin(intadults,intchildren,BoatGraderb){bg=b; parentThread=KThread.currentThread(); for(inti=0;i newKThread(newRunnable(){ publicvoidrun(){ AdultItinerary(); } }).fork(); for(inti=0;i newKThread(newRunnable(){ publicvoidrun(){ ChildItinerary(); } }).fork(); children_number_Oahu=children;adult_number_Oahu=adults;children_number_Molokai=0; adult_number_Molokai=0; lock=newLock(); children_condition_Oahu=newCondition(lock);children_condition_Molokai=newCondition(lock);adult_condition_Oahu=newCondition(lock);is_pilot=true; is_adult_go=false;is_end=false;boat_in_Oahu=true; } staticvoidAdultItinerary() {bg.initializeAdult();lock.acquire(); if(! (is_adult_go&&boat_in_Oahu)){adult_condition_Oahu.sleep(); } bg.AdultRowToMolokai();adult_number_Oahu--;adult_number_Molokai++;is_adult_go=false;boat_in_Oahu=false;children_condition_Molokai.wake();lock.release(); } staticvoidChildItinerary() {bg.initializeChild();booleanis
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 nachos 课程设计 实验 报告