CPU Schedulers Assignment

Due: Friday, December 14, midnight.
Last modified: "December 3, 2001 16:55:22 by evett"

Succesful completion of this assignment will increase the student's course GPA by 0.5. This amount will be pro-rated for partial completion.

Modify the multi-threaded scheduler in the provided code to test each of three different types of schedulers. Here is the basic Thread class. Here is (most) of the round-robin scheduler. Here is a driver for testing the round-robin scheduler. (My scheduler makes use of a simple circular queue class to implement the job queues.)

  • The first mechanism is First-Come, First-Serve (FCFS).
  • The second is Round-Robin(RR), assuming pre-emptive multitasking with 500 millisecond time quanta.
  • The third (ML) is an implementation of the multilevel feedback queue scheduler outlined on pp. 139-140, Figure 5.7. (Note that this 3rd scheduler might make use of your implementation of the first scheduling mechanism. Watch out for the different types of preemption, however.) Use FCFS for the top two queues, with 200 mSec maximum execution time in the top queue, and 300 mSec maximum in the middle queue. The bottom queue should be a round-robin with 200 millisecond time quanta. (If a job in the middle or bottom queue is pre-empted, it should maintain its position in the queue, and retain the remainder of it alloted time when is made to run again.)
  • In the ML scheduler, as jobs exhaust their time quanta, they move to the lower-priority queues, and the jobs should keep track of their "priority level", which they will maintain during execution-time. I.e., if a job, X, sinks to the 2nd queue, and is then made to run, it should be pre-empted by any new job, Z, because new jobs always enter with the highest priority level. If that new job, in turn, exhausts its quantum, or terminates, the job X is is placed again in a running state, to complete the quantum it was executing when Z arrived.

    The ML scheduler is very tricky because of the preemptive nature of the scheduler. You'll have to use calls to interrupt(), to awake the scheduler at the right moments.

    Program Input and Output

    Your program should take its input from a file, "input.txt". The file will consist of a sequence of entries separated by linefeeds. Each entry represents one of two types of events: a new job event, or a request to print the contents of the ready queue.

    A job entry indicates the submission of a job to the ready queue, and is of the form:

    JOB n s t

    Where n is a job number, a unique integer between 0 and 99, and s is the number of milliseconds elapsed since the submission of the previous job and t is the number of milliseconds of run-time required by the job, expressed as a sequence c i c i ... c. Each c and i is an integer. The c's specify the length, in milliseconds, of a cpu burst. The i's do the same of IO bursts.

    A print queue request is of the form:

    PRINT s

    Where s is the number of milliseconds after the submission of the previous job. Your program should print the contents of the ready queue for each of the three schedulers. Each queue should be printed something like:

    FCFS: RUNNING 13, HEAD--(13),22,16,5--TAIL

    Where 13, 22, 16 and 5 are job numbers, indicating that job 13 is running at the time of the PRINT, job 22 will be the next job to run, followed by 16, followed, in turn, by job 5. (Note that for the multilevel scheduler, you’ll need to print three queues.)

    After the program input is exhausted, the program should output, for each scheduler, its throughput (processes per second), average turnaround time, and average waiting time per process. The program should also generate output indicating the information of a Gannt chart: the time at which each job begins to run, or at which the CPU becomes idle.

    For extra credit, present the Gannt chart data as a true Gannt chart:

    ================================
    13   14  15  13 
    xxxxxooooxxxxoooooooo
    0         5         10
    ================================
    

    where 13, 14, 15 are job numbers, each "x" or "o" represents 50 milliseconds, and the "0..5..10" mark the total elapsed time in 100's of milliseconds. If the Gannt chart extends more than 80 columns, break it into 80 column chunks, contiguous on the page.

    Here is some sample output and sample input.

    Hints

    You may want to use Java's built-in StreamTokenizer class to read the input file. Check out the Java documentation.

    You should probably implement each of the schedulers as a class, inheriting from a common abstract class. The public interface for each such class will be the same, but the implementations will differ. Look at my basic scheduler class for guidelines.

    Note that the time of each event is implicit, being equal to the sum of the "start time-deltas" that precede it.

    Sample Code

    Here is my implementation of the basic thread class.

    Dealing with simultaneity

    If the queue of ready jobs is empty as a job is terminating or exhausting its quantum, and simultaneously a new job is being submitted, the new job does get the next quantum. If a print command occurs simultaneously with a job submission, termination, or quantum being exhausted, the print should occur after all those other events.

    Reading from files in Java

    Here is some boilerplate code for reading from a file. The "StreamTokenizer" parses the contents of the input file into "tokens", which are basically words--sequences of characters delineated by whitespace. The "try" has three associated "catch"'s because there are so many things that can go wrong with I/O operations.
              FileReader frs = null; 
              StreamTokenizer in = null; 
              try 
              { 
                //create file input and output streams 
                frs = new FileReader("input.txt");  
    
                //create a stream tokenizer wrapping file input stream 
                in = new StreamTokenizer(frs);  
    
                //read first token 
                in.nextToken(); // Get the first token 
                while (in.ttype != in.TT_EOF) // Keep going until exhausting tokens 
                { 
                  if (in.ttype == in.TT_WORD) 
                   ...  
    
                  in.nextToken(); // Get the next token 
                } 
              } // yrt 
              catch (FileNotFoundException ex) 
              { 
                  System.out.println("File not found: input.txt"); 
              } 
              catch (IOException ex) 
              { 
                  System.out.println(ex.getMessage()); 
              } 
              finally 
              { 
                try 
                { 
                    if (frs != null) frs.close(); 
                } 
                catch (IOException ex) 
                { 
                } 
               }