山东大学操作系统课程设计代码分析及设计实现及测试报告Word下载.docx
《山东大学操作系统课程设计代码分析及设计实现及测试报告Word下载.docx》由会员分享,可在线阅读,更多相关《山东大学操作系统课程设计代码分析及设计实现及测试报告Word下载.docx(59页珍藏版)》请在冰豆网上搜索。
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就绪"
);
ForkingandjoiningA_thread..."
this.joinee.fork();
this.joinee.join();
B_thread执行结束"
privateKThreadjoinee;
publicstaticclassA_threadimplementsRunnable{
A_thread(intnum){
this.num=num;
A_thread就绪"
A_thread开始执行"
//Thisshouldjustkillsomecycles
for(inti=0;
i<
this.num;
++i){
A_thread循环第"
+i+"
次"
KThread.currentThread().yield();
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<
KThread>
waitQueue;
publicvoidsleep(){
waitQueue.add(KThread.currentThread());
conditionLock.release();
conditionLock.acquire();
publicvoidwake(){
waitQueue.remove().ready();
3.2.4测试代码及结果
创建共有条件变量c2test,一个临界资源count和三个线程,thread1,thread2,thread3,初始化三个线程后thread1,thread2调用c2test.sleep()后开始“睡眠”,thread3调用c2test.wakeAll()唤醒所有线程,thread1,thead2开始交替访问临界资源count并更改其“余额”数值。
publicclassCondition2Test{
Lockcondlock=newLock();
Condition2c2test=newCondition2(condlock);
publicCondition2Test(){
publicvoidsimpleCondition2Test(){
System.out.println("
\n****Condition2Testisnowexecuting.****"
初始化账户余额为10000"
finalMyCountmyCount=newMyCount("
0000001"
10000);
//创建并发访问的账户
KThreadthread1=newKThread(newRunnable(){
newSaveThread("
张三"
myCount,2000);
张三goestosleep"
condlock.acquire();
c2test.sleep();
System.out.println("
张三reacquireslockwhenwoken."
condlock.release();
张三isawake!
!
"
myCount.save(2000,"
张三"
});
KThreadthread2=newKThread(newRunnable(){
李四"
李四goestosleep"
李四reacquireslockwhenwoken."
李四isawake!
李四"
KThreadthread3=newKThread(newRunnable(){
thread3Wakingupthethread"
condlock.acquire();
c2test.wakeAll();
condlock.release();
张三and李四wokeupbywakeAll"
thread1.fork();
thread2.fork();
thread3.fork();
thread1.join();
thread2.join();
thread3.join();
****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);
privateKThreadwaitThread;
privateConditiontimecondition;
privatelongwakeTime;
3.3.4测试代码及结果
创建5个线程,依次“睡眠”20000ticks,线程醒来后各自打印出睡眠开始时间,要求睡眠时间,醒来时间,以及实际睡眠时间。
测试代码:
publicstaticvoidselfTest(intnumOfTest){
Runnablea=newRunnable(){
AlarmTestThread();
};
for(inti=0;
i<
numOfTest;
i++){
intnumOfThreads=5;
print("
Creating"
+numOfThreads+"
numofthreads"
for(intj=0;
j<
numOfThreads;
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"
被唤醒时间:
+Machine.timer().getTime()+"
要求睡眠时间:
:
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!
speaker.wake();
listener.sleep();
intmyMessage=this.Message;
listenersize--;
returnmyMessage;
3.4.4测试代码及结果
importjava.util.ArrayList;
importjava.util.Random;
publicclassCommunicatorTest{
publicCommunicatorTest(){
Message=1;
numOfSpeakers=5;
numOfListeners=5;
communicator=newCommunicator();
publicvoidcommTest(intnum){
\nCommunicatorTest开始"