0

I wrote code to implement the Producer-Consumer problem and it seems to be working fine without the need to synchronize.Is it possible?

How do I test the code and check if it is actually working right or not? How do I know if deadlock will occur? Right now,I am not breaking out of the loops(i.e. the Producer keeps inserting and the consumer keeps consuming in an infinite loop).I am using a circular queue of size 3(for sake of simplicity) as the shared resource.

Here is my code:

import java.util.*;

public class PCImpl implements Runnable 
{
Thread t;
QforPC qObj;

 public static void main(String[] args)
 {
     QforPC qObject=new QforPC();

     //These create 2 different objects! Each object has it's own thread of execution.
     //Synchronization is needed when 2 threads use the same object
    new PCImpl("Producer",qObject);
    new PCImpl("Consumer",qObject);
 }

 PCImpl(String name,QforPC qObj)
 {
     this.qObj=qObj;
     t=new Thread(this,name);
     t.start();
 }

 public void run()
 {
         if(Thread.currentThread().getName().equals("Producer"))
         {
             while(true)
             {
                  Random rgen=new Random();
                  int n=rgen.nextInt(100);
                  if(n!=0)
                              qObj.Producer(n);
                         try
                    {
                       Thread.sleep(200);
                     }
                      catch(InterruptedException e)
                    {

                    }
               }

            }


         if(Thread.currentThread().getName().equals("Consumer"))
         {
             while(true)
                  {
                 try
               {
                 Thread.sleep(1500);
               }
                catch(InterruptedException e)
               {
                  }
              qObj.Consumer();

              }
         }

  }
}



public class QforPC 
{
int[] q={0,0,0};
int r=0,f=0;
  public void Producer(int item)
     {

         if(r!=q.length && canProducer())
         {
             q[r]=item;
             System.out.println("The item inserted into the queue is:"+ item);
             r++;
         }
         if(r==q.length && f>0)
             r=0;
         else if(r==q.length && f==q.length)
         {
             r=0;
             f=0;
         }
     }

     public void Consumer()
     {
         int item;
         System.out.println("The value of isQueue empty is:"+ isEmpty());

         if(f!=q.length && isEmpty()==false)
         {
             System.out.println("Entered the consumer method");
             item=q[f];
             System.out.println("The item fetched from the queue is:"+item);
             q[f]=0;
             f++;
         }
         if(f==q.length && r<f)
             f=0;

     }

     public boolean isEmpty()
     {
         for(int k=0;k<q.length;k++)
         {
             if(q[k]==0 && k==q.length-1)
                 return true;

         }
         return false;
     }

     public boolean canProducer()
     {
         for(int k=0;k<q.length;k++)
         {
                 if(q[k]==0)
                 return true;

         }
         return false;
     }
} 
Mathew Thompson
  • 55,877
  • 15
  • 127
  • 148
collegian
  • 65
  • 1
  • 7
  • 1
    It will probably mess up if you remove the `Sleeps`. – SwDevMan81 Dec 14 '10 at 18:59
  • 2
    Welcome to the nature of timing bugs. It'll seem to be working fine right until the point where it blows up completely. – Mark Peters Dec 14 '10 at 19:00
  • 2
    Why not separate the logic of the producer and consumer into two separate implementations of `Runnable`? This design is very ineligant and will lead to completely unmaintanable code. – Mark Peters Dec 14 '10 at 19:01
  • @Mark- So does that mean that it won't work without synchronization? Also,thanks for the suggestion! – collegian Dec 14 '10 at 19:04
  • The sad part is that your TAs will probably have no idea how to test the code properly and/or point out why there's a problem. At least if they're anything like mine were... – Karl Knechtel Dec 14 '10 at 19:26

4 Answers4

1

What you have tried to do is implement synchronization using busy-waiting. In pseudo code what you are basically doing is:

Producer()
{
   if (buffer.hasemptyspaces())
   {
      produce(buffer);
   }
   else
   {
      sleep(n);
   }
}

Consumer()
{
   if (buffer.hasfullspaces())
   {
      consume(buffer);
   }
   else
   {
      sleep(n);
   }
}

You code will work fine, till the the Producer and Consumer simultaneously try to execute produce() and consume(). In other words, either one of the This might not be very often, but is definitely possible and will definitely happen!

In Java, ConcurrentLinkedQueue to implements a wait-free algorithm for a shared buffer. I'm sure that are other implementations if you look around.

Sonny Saluja
  • 7,193
  • 2
  • 25
  • 39
  • So, this means that it can't work without synchronization in my implementation and at some point the program will crash? – collegian Dec 14 '10 at 19:08
  • 1
    Yes. When implementing threads and shared data, it is useful to think "If there is a way to interleave your threads in such a way that they will crash, the scheduler will find it". – Sonny Saluja Dec 14 '10 at 19:10
0

There's no such thing as the Producer-Consumer problem. Producer-Consumer is a design pattern that may or may not be an effective implementation of a solution to a problem, not a problem in and of itself.

I'm SURE there are plenty of producer-consumer implementations that don't require synching. It entirely depends on what you're trying to accomplish and what kind of data you're producing/consuming.

Also, you have to have a problem to solve if you want to say you're implementation works without synchronizing. Works at doing what? I have no idea what you're doing.

Falmarri
  • 47,727
  • 41
  • 151
  • 191
0

It can be done with a lock free queue, but not like this, i recommend that you read Java Concurrency in Practice. If your code is access by multiple threads at the same time you will have many erros on that, you have publication and syncronizations problems!! But like Farlmarri said it depends on the usage of this code.

DVD
  • 1,744
  • 3
  • 17
  • 34
0

you are actually not solving the producer/consumer problem but just walking around it :) Your code works because of the timing and because of the fact if one of the two threads fails putting/retrieving the resource it asks for it basically sleeps for a while and tries again. Although this worsk (when you do not have to immediatly handle an event) it wastes CPU time.

That is why semaphores are strongly suggested to address this kind of issue as you can read here

http://en.wikipedia.org/wiki/Producer-consumer_problem

bye

Andrea Sindico
  • 7,358
  • 6
  • 47
  • 84
  • Actually, it looks like the OP's implementation is pretty similar to the implementation listed in that article as "inadequate". – Mark Peters Dec 14 '10 at 19:26