voidptr
voidptr

Reputation: 31

Consumer Producer

ProdCom.java (driver class)

import static java.lang.System.out;


public class ProdCom{
    static int full = 50;
    static int mutx = 0;
    static int empty = 0;
    static int currentSize = 0;
   
    public static void acquire(){
        while (mutx == 1);
        
        mutx++;
        
    }
    
    public static void release(){
        mutx--;
    }
    
 
    public static void main(String args[]){
        Thread t = new Thread(new Producerr());
        Thread t1 = new Thread(new Consumerr());
                
        t.start();
        t1.start();
    }
   
    
}

Producerr.java

class Producerr implements Runnable{
        
        
        public void wwait(){
            while (ProdCom.currentSize >= ProdCom.full){
                
            } 
            
        } public void signal(){
            ProdCom.currentSize++;
        }
        
        public void run(){
            do{
                this.wwait();
                
                ProdCom.acquire();
                
                out.println("Num elements" + ProdCom.currentSize);
                out.println("producing!");
                
                ProdCom.release();
                this.signal();
            } while (true);
        }
    }

Consumerr.java

class Consumerr implements Runnable{
        public void wwait(){
            while (ProdCom.currentSize <= 0){
                out.println("inside consumer wait: ");
                out.println("number of elements: " + ProdCom.currentSize);
            } 
            
        } public void signal(){
            ProdCom.currentSize--;
            
        }
        
      
        public void run(){
            do{
               
                this.wwait();
                ProdCom.acquire();
               
                out.println("Num elements" + ProdCom.currentSize);
                out.println("Consuming!");
                
                ProdCom.release();
                this.signal();
            } while (true);
        } 
    }
           

Above is my solution to the consumer-producer problem. The driver class ProdCom has variables full, empty and mutx for controlling producer t and consumer t1's access to the variable currentSize (Thus simulating the current number of items in a buffer). But when I run the code, the output seems to indicate t1 and t aren't taking turns to change currentSize, instead one of them repeats forever and gets stuck...I'm wondering why? Thanks.

Upvotes: 1

Views: 54

Answers (2)

Joni
Joni

Reputation: 111409

The Java memory models allows threads to cache the values of variables, and different threads to have different caches. This means that the spin lock in acquire easily becomes an infinite loop: the thread in acquire may use the cached value mutx = 1 and never read the updated value from main memory:

while (mutx == 1); // infinite loop even if another thread changes mutx

Another problem is that the ++ and -- operators are not atomic: they read the value of the variable, modify it, and write it back. If two threads run currentSize++ and currentSize-- at the same time it is possible one of them is lost.

You can fix these problems by using an AtomicInteger object and its methods instead of int, for example in ProdCom:

static AtomicInteger currentSize = new AtomicInteger(0);
static AtomicInteger mutx = new AtomicInteger(0);

public static void acquire() {
    while (!mutx.compareAndSet(0, 1));
}

public static void release() {
    mutx.set(0);
}

Upvotes: 1

Ronald
Ronald

Reputation: 2882

I've improved your code a bit, and you'll notice that many of the concepts mentioned by Joni are considered.

ProdCom.java

import java.lang.*;

public class ProdCom{
    static final int FULL = 50;
    static final int EMPTY = 0;

    static volatile int mutx = 0;
    static volatile int currentSize = 0;
    static Object lockObject = new Object();
   
    public static void acquire(){
        /* since mutx is defined volatile, the spinlock works,
           but you reconsider this approach. There are cheaper
           methods of heating the room */
        while (mutx == 1);
        
        mutx++;
        
    }

    public static boolean isEmpty() {
        synchronized(lockObject) {
            if (currentSize <= EMPTY) return true;
            return false;
        }
    }
    
    public static boolean isFull() {
        synchronized(lockObject) {
            if (currentSize >= FULL) return true;
            return false;
        }
    }

    public static int getCurrentSize() {
        synchronized(lockObject) {
            return currentSize;
        }
    }
    
    public static void release(){
        mutx--;
    }

    public static void incCurrentSize()
    {
        synchronized(lockObject) {
            currentSize++;
        }
    }
    
    public static void decCurrentSize()
    {
        synchronized(lockObject) {
            currentSize--;
        }
    }
    
 
    public static void main(String args[]){
        Thread t = new Thread(new Producerr());
        Thread t1 = new Thread(new Consumerr());
                
        t.start();
        t1.start();
    }
   
    
}

Consumerr.java

import java.lang.*;

class Consumerr implements Runnable {

    public void wwait() {
        while (ProdCom.isEmpty()){
            System.out.println("inside consumer wait: ");
            System.out.println("number of elements: " + ProdCom.getCurrentSize());
            try {
                /* we don't spinlock here */
                Thread.sleep(50);
            } catch (Exception e) {
                /* do nothing */
            }
        } 
        
    }

    public void signal(){
        ProdCom.decCurrentSize();
        
    }
    
      
    public void run(){
        do{
            this.wwait();
            ProdCom.acquire();
               
            System.out.println("Num elements " + ProdCom.getCurrentSize());
            System.out.println("Consuming!");
            this.signal();
            
            ProdCom.release();
        } while (true);
    } 
}

Producerr.java

import java.lang.*;

class Producerr implements Runnable {

    public void wwait(){
        while (ProdCom.isFull()){
            try {
                Thread.sleep(50);
            } catch(Exception e) { /* do nothing */ }
        } 

    }
    public void signal(){
        ProdCom.incCurrentSize();
    }

    public void run(){
        do {
            this.wwait();

            ProdCom.acquire();

            System.out.println("Num elements : " + ProdCom.getCurrentSize());
            System.out.println("producing!");
            this.signal();

            ProdCom.release();
        } while (true);
    }
}

Upvotes: 1

Related Questions