0
votes

I'm doing a CPU scheduling simulator project for my OS course. The program should consist of two threads: producer and consumer threads. The producer thread includes the generator that generates processes in the system and the long term scheduler that selects a number of processes and put them in an Object called Buffer of type ReadyQueue (which is a shared object by consumer and producer). The consumer thread includes the short term scheduler which takes processes from the queue and starts the scheduling algorithm. I wrote the whole program without using threads and it worked properly but now I need to add threads and I never used threads so I appreciate if someone can show me how to modify the code that I'm showing below to implement the required threads.

Here's the Producer class implementation:

public class Producer extends Thread{

    ReadyQueue Buffer = new ReadyQueue(20); // Shared Buffer of size 20 between consumer and producer  
    JobScheduler js = new JobScheduler(Buffer);

    private boolean systemTerminate = false; // Flag to tell Thread that there are no more processes in the system 

    public Producer(ReadyQueue buffer) throws FileNotFoundException{
        Buffer = buffer;
        Generator gen = new Generator();   // Generator generates processes and put them in a vector called memory     
        gen.writeOnFile();
    }

    @Override
    public  void run() {

        synchronized(this){
            js.select();  // Job Scheduler will select processes to be put in the Buffer

            Buffer = (ReadyQueue) js.getSelectedProcesses();

            while(!Buffer.isEmpty()){      
                try {
                    wait();     // When Buffer is empty wait until getting notification
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                systemTerminate = js.select();
                Buffer = (ReadyQueue) js.getSelectedProcesses();
                if(systemTerminate)     // If the flag's value is true the thread yields
                    yield();
            }
        }
    }   

    public ReadyQueue getReadyQueue(){
        return Buffer;
    }
}

This is the Consumer class implementation:

public class Consumer extends Thread{

    ReadyQueue Buffer = new ReadyQueue(20);
    Vector<Process> FinishQueue = new Vector<Process>();
    MLQF Scheduler ;
    public Consumer(ReadyQueue buffer){
        Buffer = buffer;
        Scheduler = new MLQF(Buffer,FinishQueue);   // An instance of the multi-level Queue Scheduler
    }

    @Override
    public  void run() {
        int count = 0;         // A counter to track the number of processes

        while(true){
            synchronized(this){
                Scheduler.fillQueue(Buffer);    // Take contents in Buffer and put them in  a separate queue in the scheduler
                        Scheduler.start();              // Start Scheduling algorithm
                count++;
            }
            if(count >= 200)   // If counter exceeds the maximum number of processes thread must yeild
                yield();
            notify();               // Notify Producer thread when buffer is empty
        }
    }

    public void setReadyQueue(ReadyQueue q){
        Buffer = q;
    }
}

This is the main Thread:

public class test {

    public static void main(String[] args) throws FileNotFoundException,InterruptedException {       
        ReadyQueue BoundedBuffer = new ReadyQueue(20);
        Producer p = new Producer(BoundedBuffer);
        Consumer c = new Consumer(p.getReadyQueue());
        p.start();
        System.out.println("Ready Queue: "+p.getReadyQueue());
        p.join();
        c.start();
        c.join();
        }
}

Thank you in advance.

1

1 Answers

1
votes

One problem with your code is that it suffers from a common bug in multithreaded producer/consumer models. You must use a while look around the wait() calls. For example:

try {
    // we must do this test in a while loop because of consumer race conditions
    while(!Buffer.isEmpty()) {
        wait();     // When Buffer is empty wait until getting notification
        ...
    }
} catch (InterruptedException e) {
    e.printStackTrace();
}

The issue is that if you have multiple threads that are consuming, you may notify a thread but then another thread made come through and dequeue the item that was just added. When a thread is moved from the WAIT queue to the RUN queue after being notified, it will usually be put at the end of the queue, possibly behind other threads waiting to synchronize on this.

For more details about that see my documentation about this.