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;iintnumOfThreads=5;
print("Creating"+numOfThreads+"numofthreads");
for(intj=0;jKThreadthread=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开始");