山东大学操作系统课程设计代码分析及设计实现及测试报告.docx

上传人:b****8 文档编号:9606029 上传时间:2023-02-05 格式:DOCX 页数:59 大小:51.10KB
下载 相关 举报
山东大学操作系统课程设计代码分析及设计实现及测试报告.docx_第1页
第1页 / 共59页
山东大学操作系统课程设计代码分析及设计实现及测试报告.docx_第2页
第2页 / 共59页
山东大学操作系统课程设计代码分析及设计实现及测试报告.docx_第3页
第3页 / 共59页
山东大学操作系统课程设计代码分析及设计实现及测试报告.docx_第4页
第4页 / 共59页
山东大学操作系统课程设计代码分析及设计实现及测试报告.docx_第5页
第5页 / 共59页
点击查看更多>>
下载资源
资源描述

山东大学操作系统课程设计代码分析及设计实现及测试报告.docx

《山东大学操作系统课程设计代码分析及设计实现及测试报告.docx》由会员分享,可在线阅读,更多相关《山东大学操作系统课程设计代码分析及设计实现及测试报告.docx(59页珍藏版)》请在冰豆网上搜索。

山东大学操作系统课程设计代码分析及设计实现及测试报告.docx

山东大学操作系统课程设计代码分析及设计实现及测试报告

操作系统课程设计报告

班级:

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;

privateLinkedListwaitQueue;

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开始");

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1