So I am retaking my Operating Systems class, and this time around, we're working with Java. Same project as last semester (simulate putting processes on a pending list, moving them, when the time is right, to the ready list, run them, and when they run to completion, move them to a finished list), different language. This time around, I am having trouble with the concurrency part. Mainly, getting it so I can run the threads that check whether there are pending processes (and if those processes can be moved to the ready list), runs the process, checks whether or not the process has completed, or has run out of time on the CPU/needs to be moved back to the ready list, THEN runs something to increment the clock, which (based on the impression I got from my prof) needed to be done separately. My clock is an AtomicInteger... oh hell, let me just post the mess that I already have. Just feels like things are not running quite right - I am part of the way there, or a big part of the way there, rather, but am missing something to make it work right/need to figure out not just what that is, but how to fix it. Another issue in my code that I need help fixing is if a running process runs out of time, and needs to be moved back to the ready list... that seems to get me stuck in an infinite loop, and I am having trouble debugging the problem (derping hard). Yes, I am aware that there are probably a shitton of issues, and most likely I have also neglected to be fully aware of issues regarding threads trying to modify data at the same time, which is why I am asking for help. Just a note: In the code, I put a few PCBs on the pending list. This is just for testing purposes, I have a file containing data that the prof. gave us, which I will use to create PCBs/push them onto the waiting list, but I want to make sure all these core components work BEFORE doing that. Code (Text): import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; public class simulation { public static void main(String[] args){ // VARAIBLES: // ATOMIC VARIABLES: AtomicInteger clock = new AtomicInteger(0); // Our system clock // LISTS: List<pcb> pendingList = Collections.synchronizedList(new ArrayList<pcb>()); // For processes that have yet to enter the system List<pcb> readyList = Collections.synchronizedList(new ArrayList<pcb>()); // For processes that are ready, but need a CPU to be come available List<pcb> finishedList = Collections.synchronizedList(new ArrayList<pcb>()); // For processes that have completed running pendingList.add(new pcb(30,1,2)); pendingList.add(new pcb(31,2,1)); pendingList.add(new pcb(32,3,1)); pendingList.add(new pcb(33,4,1)); pendingList.add(new pcb(34,5,1)); pendingList.add(new pcb(35,6,1)); // PROCESSOR: processor sysProcessor = new processor(1); // THREADS WITH RUNNABLES FOR DATA PROCESSING/SIMULATION Thread clockThread = new Thread(new clockMgr(clock)); Thread pendingCheckerThread = new Thread(new checkPending(pendingList, readyList, clock)); Thread schedulerThread = new Thread(new scheduler(sysProcessor, readyList)); Thread runProcessThread = new Thread(new processRunner(sysProcessor, readyList, finishedList)); // Loop until every list except for the finish list is empty - which would signify all work has completed while(!pendingList.isEmpty() || !readyList.isEmpty() || (sysProcessor.getRunningProcess() != null)){ pendingCheckerThread.run(); schedulerThread.run(); runProcessThread.run(); try { pendingCheckerThread.join(); schedulerThread.join(); runProcessThread.join(); } catch (InterruptedException e) { } clockThread.run(); try { clockThread.join(); } catch (InterruptedException e) { } } System.out.print("Simulation finished. Final runtime: " + clock.get() + "\n"); System.exit(0); } public static class pcb { // VARIABLES: private int processID; // Process ID private int timeEntry; // Time a process is supposed to enter the ready queue private int timeNeeded; // Amount of time the process needs on the CPU to finish executing private int timeExecuting; // Amount of time the process has been executing on the CPU. Once this value matches timeNeeded, the process will complete, and be moved to the finished queue. // CONSTRUCTOR FUNCTIONS: // This constructor takes in 3 integers - one for each piece of data in the PCB, sets each variable to that data, except for timeExecuting, which defaults to 0. public pcb(final int inPid, final int inTimeEntry, final int inTimeNeededToFinish){ processID = inPid; timeEntry = inTimeEntry; timeNeeded = inTimeNeededToFinish; timeExecuting = 0; } // ACCESSOR FUNCTIONS: /* FUNCTION: public int getPID(); * Inputs: none * Returns: processID */ public int getPID(){return processID;} /* FUNCTION: public String getPIDAsString(); * Inputs: none * Returns: processID as a String */ public String getPIDAsString(){return Integer.toString(processID);} /* FUNCTION: public int getTimeEntry(); * Inputs: none * Returns: timeEntry */ public int getTimeEntry(){return timeEntry;} /* FUNCTION: public String getTimeEntryAsString(); * Inputs: none * Returns: timeEntry as a String */ public String getTimeEntryAsString(){return Integer.toString(timeEntry);} /* FUNCTION: public int getTimeExecuting(); * Inputs: none * Returns: timeExecuting */ public int getTimeExecuting(){return timeExecuting;} /* FUNCTION: public String getTimeExecutingAsString(); * Inputs: none * Returns: timeExecuting as a String */ public String getTimeExecutingAsString(){return Integer.toString(timeExecuting);} /* FUNCTION: public int getTimeNeededToFinish(); * Inputs: none * Returns: timeNeededToFinish */ public int getTimeNeededToFinish(){return timeNeeded;} /* FUNCTION: public String getTimeNeededToFinishAsString(); * Inputs: none * Returns: timeNeededToFinish as a String */ public String getTimeNeededAsString(){return Integer.toString(timeNeeded);} // MUTATOR FUNCTIONS: /* FUNCTION: public void setPID(final int inPID) * Inputs: final int inPID * Returns: nothing - sets processID's value to inPID's value */ public void setPID(final int inPID){processID = inPID;} /* FUNCTION: public void setPriority(final int inPriority) * Inputs: final int inPriority * Returns: nothing - sets processID's value to inPriority's value */ public void setTimeEntry(final int inTimeEntry){timeEntry = inTimeEntry;} /* FUNCTION: public void setTimeExecuting(final int inTimeExecuting) * Inputs: final int inTimeExecuting * Returns: nothing - sets timeExecuting's value to inTimeExecuting's value */ public void setTimeExecuting(final int inTimeExecuting){timeExecuting = inTimeExecuting;} /* FUNCTION: public void incrementTimeExecuting() * Inputs: none * Returns: nothing - function just increments timeExecuting's value. */ public void incrementTimeExecuting(){timeExecuting++;} /* FUNCTION: public void setTimeNeededToFinish(final int inTimeNeededToFinish) * Inputs: final int inTimeNeededToFinish * Returns: nothing - sets timeNeededToFinish's value to inTimeNeededToFinish's value */ public void setTimeNeeded(final int inTimeNeededToFinish){timeNeeded = inTimeNeededToFinish;} } public static class processor{ private int burstTime; private pcb runningProcess; public processor(final int inBurstTime){ burstTime = inBurstTime; runningProcess = null; } public pcb getRunningProcess(){return runningProcess;} // Retrieve the running process' pcb without removing it from the processor public pcb removeRunningProcess(){ pcb pToReturn = runningProcess; runningProcess = null; return pToReturn; } public int getBurstTime(){return burstTime;} public void setRunningProcess(pcb inRunningProcess){runningProcess = inRunningProcess;} public void setBurstTime(final int inBurstTime){burstTime = inBurstTime;} } public static class clockMgr implements Runnable{ private AtomicInteger sysClock; static ReentrantLock clockLock = new ReentrantLock(true); public clockMgr(AtomicInteger inClock){ sysClock = inClock; } public void run() { clockLock.lock(); try { sysClock.incrementAndGet(); } catch(Exception e) { } finally{ clockLock.unlock(); } } } public static class checkPending implements Runnable{ private AtomicInteger sysClock; private List<pcb> pendingList; private List<pcb> readyList; public checkPending(List<pcb> inPendingList, List<pcb> inReadyList, AtomicInteger inClock){ sysClock = inClock; pendingList = inPendingList; readyList = inReadyList; } public void run(){ try{ if(pendingList.isEmpty()){return;} for(Iterator<pcb> i = pendingList.iterator(); i.hasNext();) { pcb pendingProcess = i.next(); if(sysClock.get() == pendingProcess.getTimeEntry()){ System.out.print("Moving process PID " + pendingProcess.getPID() + " from the pending list, to the ready list.\n\n"); readyList.add(pendingProcess); pendingList.remove(pendingProcess); } } } catch (Exception e) { } } } public static class processRunner implements Runnable{ private processor sysProcessor; private List<pcb> readyList; private List<pcb> finishedList; public processRunner(processor inSysProcessor, List<pcb> inReadyList, List<pcb> inFinishedList){ sysProcessor = inSysProcessor; readyList = inReadyList; finishedList = inFinishedList; } public void run(){ try{ // If the time running is greater or equal to the time needed to run, move the process to the finished queue if((sysProcessor.getRunningProcess().getTimeExecuting() == sysProcessor.getRunningProcess().getTimeNeededToFinish())){ System.out.print("Process PID " + sysProcessor.getRunningProcess().getPID() + " has finished executing. Moving it to the finished list.\n\n"); finishedList.add(sysProcessor.removeRunningProcess()); sysProcessor.setRunningProcess(null); return; } // If the process runs out of time, it will get put on the back of the ready list else if((sysProcessor.getRunningProcess().getTimeExecuting() != 0) && ((sysProcessor.getRunningProcess().getTimeExecuting() % sysProcessor.getBurstTime()) == 0)){ System.out.print("Process PID " + sysProcessor.getRunningProcess().getPID() + " has run out of CPU time, moving it back to the ready list.\n\n"); readyList.add((readyList.size() - 1),sysProcessor.removeRunningProcess()); return; } sysProcessor.getRunningProcess().incrementTimeExecuting(); } catch (Exception e) { } } } public static class scheduler implements Runnable{ private processor sysProcessor = null; private List<pcb> readyList; public scheduler(processor inSysProcessor, List<pcb> inReadyList){ sysProcessor = inSysProcessor; readyList = inReadyList; } public void run(){ if(sysProcessor.getRunningProcess() != null){return;} else{ // If the processor has no pcb on it currently, // Check to see if the ready list is empty: if(readyList.isEmpty()){return;} // If the list is not empty, take a pcb off the front of it, give it to the processor. sysProcessor.setRunningProcess(readyList.remove(0)); System.out.print("Running process PID " + sysProcessor.getRunningProcess().getPID() + ".\n\n"); } } } }