Currently I am working on a Java question that is related to Java thread and concurrency. The thread should handles Multiple Processes, Multiple Processors and Single Priority Queue.
It has 5 main functions which are set_number_of_processors, reg, start, schedule, and terminate.
My code works fine with 3 sessions. However, when it has 4 sessions. It shows errors. I need some help in figuring what is the problems with my code.
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition; //Note that the 'notifyAll' method or similar
import java.util.ArrayList;
import java.util.LinkedList;
public class OS implements OS_sim_interface {
int pid = 0;
int numProcessors;
int numAvailableProcessors;
ArrayList<Process> processes = new ArrayList<Process>(); //An ArrayList to store the processes
ArrayList<Process>[] runningProcesses;
LinkedList<Process> readyQueue = new LinkedList<Process>(); //A LinkedList to store the waiting processes
//lock and condition variables
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
OS(){
//default constructor
}
@Override
public void set_number_of_processors(int nProcessors) {
if(nProcessors < 1){
System.out.println("Number of processors must be greater than 1");
}
runningProcesses = new ArrayList[nProcessors];
for (int i = 0; i < nProcessors; i++) {
runningProcesses[i] = new ArrayList<Process>();
}
numAvailableProcessors = nProcessors;
numProcessors = nProcessors;
}
@Override
public int reg(int priority) {
if(priority <= 0){
System.out.println("Please give a valid priority (minimum 1)");
return -1;
}else{
//Create a new process
Process process = new Process(pid, priority);
//Add the process to the list of processes
processes.add(process);
pid++; //Increment the process ID recorded by OS
return process.ID;
}
}
@Override
public void start(int ID) {
if(ID < 0 || ID >= processes.size()){
System.out.println("Invalid process ID");
}else{
Process currProcess = processes.get(ID);
int currProcessor = 0;
for (int i = 0; i < numProcessors; i++) {
if (runningProcesses[i].isEmpty()) {
currProcessor = i;
break;
}
}
//Check if there are available processors
if(numAvailableProcessors > 0){
lock.lock();
try{
currProcess.run();
runningProcesses[currProcessor].add(currProcess);
System.out.println(currProcess.name + " is running on Processor-" + currProcessor);
numAvailableProcessors--;
}catch(Exception e){
System.out.println("Hi, I'm your exception: " + e);
}finally {
lock.unlock();
}
}else {
lock.lock();
try{
readyQueue.add(currProcess);
condition.await();
System.out.println(currProcess.name + " is added in readyQueueStart");
}catch(Exception e){
System.out.println("Hi, I'm your exception: " + e);
}finally {
lock.unlock();
}
}
}
}
@Override
public void schedule(int ID) {
if(ID < 0 || ID >= processes.size()){
System.out.println("Invalid process ID");
}else{
Process currProcess = processes.get(ID);
int currProcessor = 0;
for (int i = 0; i < numProcessors; i++) {
if (runningProcesses[i].contains(currProcess)) {
currProcessor = i;
break;
}
// else do nothing
}
if(!readyQueue.isEmpty()){
lock.lock();
try{
//add the current process to readyQueue
readyQueue.add(currProcess);
System.out.println(currProcess.name + " is added in readyQueue");
runningProcesses[currProcessor].remove(currProcess);
//wake up the waiting process
condition.signal();
lock.unlock();
//wait for the process to finish
lock.lock();
//run next process in readyQueue
Process newProcess = readyQueue.poll();
newProcess.run();
runningProcesses[currProcessor].add(newProcess);
System.out.println(newProcess.name + " is scheduled running on Processor-" + currProcessor);
//wait for the process to finish
condition.await();
}catch(Exception e){
System.out.println("Hi, I'm your exception: " + e);
}finally {
lock.unlock();
}
return;
}else{
System.out.println(currProcess.name + " is already running on Processor-" + currProcessor);
}
}
}
@Override
public void terminate(int ID) {
if(ID < 0 || ID >= processes.size()){
System.out.println("Invalid process ID");
}else{
Process currProcess = processes.get(ID);
int currProcessor = 0;
for (int i = 0; i < numProcessors; i++) {
if (runningProcesses[i].contains(currProcess)) {
currProcessor = i;
break;
}
// else do nothing
}
if(readyQueue.isEmpty()){
System.out.println(currProcess.name + " is terminated");
return;
}else{
lock.lock();
try{
//remove the current process from runningProcesses
runningProcesses[currProcessor].remove(currProcess);
System.out.println(currProcess.name + " is terminated");
//wake up the waiting process
condition.signal();
//run next process in readyQueue
Process newProcess = readyQueue.poll();
newProcess.run();
runningProcesses[currProcessor].add(newProcess);
System.out.println(newProcess.name + " is scheduled running on Processor-" + currProcessor);
}catch(Exception e){
System.out.println("Hi, I'm your exception: " + e);
}finally {
lock.unlock();
}
}
}
}
class Process extends Thread{
int ID;
int priority;
String name;
Process(int ID, int priority) {
this.ID = ID;
this.priority = priority;
this.name = "Process-" + ID;
}
}
}
Thread Class: Default
class ProcessSimThread2 extends Thread {
int pid = -1;
int start_session_length=0;
OS os;
ProcessSimThread2(OS os){this.os = os;} //Constructor stores reference to os for use in run()
public void run(){
os.start(pid);
events.add("pid="+pid+", session=0");
try {Thread.sleep(start_session_length);} catch (InterruptedException e) {e.printStackTrace();}
os.schedule(pid);
events.add("pid="+pid+", session=1");
os.schedule(pid);
events.add("pid="+pid+", session=2");
os.terminate(pid);
events.add("pid="+pid+", session=3"); //Error occured at this session. It works fine if i commented this out
};
};
Test Class: Default
public void test(){
System.out.println("\n\n\n*********** test *************");
events = new ConcurrentLinkedQueue<String>(); //List of process events
//Instantiate OS simulation for two processors
OS os = new OS();
os.set_number_of_processors(2);
int priority1 = 1;
//Create two process simulation threads:
int pid0 = os.reg(priority1);
ProcessSimThread2 p0 = new ProcessSimThread2(os);
p0.start_session_length = 250; p0.pid = pid0; //p0 grabs first processor and keeps it for 250ms
int pid1 = os.reg(priority1);
ProcessSimThread2 p1 = new ProcessSimThread2(os);
p1.start_session_length = 50; p1.pid = pid1; //p1 grabs 2nd processor and keeps it for 50ms
int pid2 = os.reg(priority1);
ProcessSimThread2 p2 = new ProcessSimThread2(os);
p2.start_session_length = 0; p2.pid = pid2; //p2 tries to get processor straight away but has to wait for p1 os.schedule call
//Start the treads making sure that p0 will get to its first os.start()
p0.start();
sleep(20);
p1.start();
sleep(25); //make sure that p1 has grabbed a processor before starting p2
p2.start();
//Give time for all the process threads to complete:
sleep(test_timeout);
String[] expected = { "pid=0, session=0", "pid=1, session=0", "pid=2, session=0", "pid=1, session=1", "pid=2, session=1", "pid=1, session=2", "pid=2, session=2","pid=1, session=3", "pid=2, session=3", "pid=0, session=1", "pid=0, session=2", "pid=0, session=3"};
System.out.println("\nUR4 - NOW CHECKING");
//Check expected events against actual:
String test_status = "UR4 PASSED";
if (events.size() == expected.length) {
Iterator <String> iterator = events.iterator();
int index=0;
while (iterator.hasNext()) {
String event = iterator.next();
if (event.equals(expected[index])) System.out.println("Expected event = "+ expected[index] + ", actual event = " + event + " --- MATCH");
else {
test_status = "UR3 FAILED - NO MARKS";
System.out.println("Expected event = "+ expected[index] + ", actual event = " + event + " --- ERROR");
}
index++;
}
} else {
System.out.println("Number of events expected = " + expected.length + ", number of events reported = " + events.size());
test_status = "UR4 FAILED - NO MARKS";
}
System.out.println("\n" + test_status);
}
Current Output:
Process-0 is running on Processor-0
Process-1 is running on Processor-1
Process-1 is added in readyQueue
Process-2 is scheduled running on Processor-1
Process-2 is added in readyQueueStart
Process-2 is added in readyQueue
Process-1 is scheduled running on Processor-1
Process-1 is added in readyQueue
Process-2 is scheduled running on Processor-1
Process-2 is added in readyQueue
Process-1 is scheduled running on Processor-1
Process-1 is terminated
Process-2 is scheduled running on Processor-1
Process-2 is terminated
Process-0 is already running on Processor-0
Process-0 is already running on Processor-0
Process-0 is terminated
UR4 - NOW CHECKING
Expected event = pid=0, session=0, actual event = pid=0, session=0 --- MATCH
Expected event = pid=1, session=0, actual event = pid=1, session=0 --- MATCH
Expected event = pid=2, session=0, actual event = pid=2, session=0 --- MATCH
Expected event = pid=1, session=1, actual event = pid=1, session=1 --- MATCH
Expected event = pid=2, session=1, actual event = pid=2, session=1 --- MATCH
Expected event = pid=1, session=2, actual event = pid=1, session=2 --- MATCH
Expected event = pid=2, session=2, actual event = pid=1, session=3 --- ERROR
Expected event = pid=1, session=3, actual event = pid=2, session=2 --- ERROR
Expected event = pid=2, session=3, actual event = pid=2, session=3 --- MATCH
Expected event = pid=0, session=1, actual event = pid=0, session=1 --- MATCH
Expected event = pid=0, session=2, actual event = pid=0, session=2 --- MATCH
Expected event = pid=0, session=3, actual event = pid=0, session=3 --- MATCH
- Thread safe' and 'synchronized' classes (e.g. those in java.util.concurrent) other than the two imported above MUST not be used.
- keyword 'synchronized', or any other thread safe classes or mechanisms are not allowed
- any delays or 'busy waiting' (spin lock) methods are not allowed