package nachos.threads; import nachos.machine.*; import java.util.Random; /** * A Tester for the Communicator class */ public class CommunicatorTest { /** * CommunicatorTest class, which has threads do a bunch of "random" * rendez-vous, producing output that indicates whether communicating * threads do indeed rendez-vous or not. */ /** * RVThread class, which implements a thread that * does a bunch of rendez-vous. */ private static class RVThread implements Runnable { /* Constructor */ RVThread(String name, Communicator comm, boolean isSpeaker, int howMany, Communicator commFinished, Random rng) { this.name = name; this.comm = comm; this.isSpeaker = isSpeaker; this.howMany = howMany; this.commFinished = commFinished; this.rng = rng; } /** Method to generate a random number of ticks that * needs to be spent waiting before attempting a * speak/listen actions. The number of ticks is * generated to be between minDelay and maxDelay, inclusive */ private int randomDelay() { return minDelay+rng.nextInt(1+maxDelay - minDelay)-1; } /** Method to generate a random word that a speaker * will speak through the Communicator. */ private int randomWord() { return rng.nextInt(50); /* between 0 and 50 */ } /** run() method for the RVThread. This method loops howMany * times. During this loop the thread waits some random * amount of time, then speaks or listen, depending on * whether this.isSpeaker is sets to true or false. */ public void run() { System.out.println("** "+name+" begins."); /* Main loop */ for (int i=0; i < howMany; i++) { /* Sleep for some random delay */ int randomDelay = randomDelay(); System.out.println("** "+name+": Sleeping for "+randomDelay+ " (i.e., until time="+ (randomDelay+Machine.timer().getTime())+")"); ThreadedKernel.alarm.waitUntil(randomDelay); System.out.println("** "+name+": Done sleeping! (time="+ Machine.timer().getTime()+")"); if (isSpeaker) { /* I am a speaker and I speak my word */ int randomWord = randomWord(); System.out.println("** "+name+": Speaking "+randomWord+ " (time="+Machine.timer().getTime()+")"); comm.speak(randomWord); System.out.println("** "+name+": Spoke and Returned (time="+ Machine.timer().getTime()+")"); } else { /* I am a listener and I listen */ System.out.println("** "+name+": Listening (time="+ Machine.timer().getTime()+")"); int word = comm.listen(); System.out.println("** "+name+": Listened and got "+word+ " (time="+Machine.timer().getTime()+")"); } } /* Exits and signals it to the main thread */ commFinished.speak(-1); System.out.println("** "+name+" exits."); } /* My name */ private String name; /* The Communicator for speaking/listening */ private Communicator comm; /* True if I am a speaker, false if I am a listener */ private boolean isSpeaker; /* The number of iterations */ private int howMany; /* The Communicator for signaling that I am done */ private Communicator commFinished; /* Random number generator */ private Random rng; } /** * Tests whether this module is working. */ public static void runTest() { System.out.println("**** Communicator testing begins ****"); /* Create a random number generator */ Random rng = new Random(); /* Create the communicator on which RVThreads communicate */ Communicator comm = new Communicator(); /* Create the communicator for listening to terminations */ Communicator commFinished = new Communicator(); /* Create rendezvous threads and fork them*/ KThread rvs[] = new KThread[numRVThreads]; for (int i=0; i < numRVThreads; i++) { if (i%2 == 0) { /* Creating a speaker */ rvs[i] = new KThread(new RVThread("RV-Thread(speaker) #"+i, comm,true,howMany,commFinished,rng)); rvs[i].setName("RV-Thread(speaker) #"+i); } else { /* Creating a listener */ rvs[i] = new KThread(new RVThread("RV-Thread(listener) #"+i, comm,false,howMany,commFinished,rng)); rvs[i].setName("RV-Thread(listener) #"+i); } /* fork() */ rvs[i].fork(); } /* Wait for all threads to signal that they're done, * which is done via a Communicator for good measures */ for (int i=0; i < numRVThreads; i++) { commFinished.listen(); System.out.println("Acknowledged one thread exit."); } System.out.println("**** Communicator testing ends ****"); } /* Number of Threads. Must be EVEN!! */ private static final int numRVThreads = 8; /* Number of RV actions per thread */ private static final int howMany = 5; /* Bounds on delay between attempts to speak/listen */ private static final int minDelay = 10000; private static final int maxDelay = 1000000; }