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.)
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.
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:
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 ================================
Here is some sample output and sample input.
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.
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) { } }