title: Producer and consumer with semaphores, multiple pthreads, 2 buffers
body: <p>OK.  So I have 2 buffers, implemented as heap.  It has an init, insert, and delete function.  The priority in this case does not matter though.  </p>
  
  <p>For each buffer, there are 3 producer threads producing an item (letter) and inserting it into a buffer.  Three producers for a buffer holding uppercase letters, and three for a buffer holding lowercase letters.  Obviously only 1 producer may append at a time to a buffer.</p>
  
  <p>There are 10 consumer threads.  These threads can access either buffer, but only up to 3 at a time per buffer, and not when a producer is producing.  I am trying to instruct the threads to go first to the buffer with more items in it, then the other.</p>
  
  <p>My problem is with deadlocks I believe.  I am getting segmentation faults, so I assume that my semaphores are not working correctly (I have not implemented them correctly).  </p>
  
  <p>I first worked on this problem using a single buffer, with multiple consumers/producers and was able to get it to work.  I have basically segmented the 1 buffer solution into multiple parts.</p>
  
  <p>I'm using 3 semaphores for each buffer.  A mutex, so only 1 item can take or append something per buffer.  These are named mutex and mutex2.  emptycount and fillcount are the counting sems used that start at the max_buffer_size and 0 respectively.</p>
  
  <p>The consumers must take a letter from each buffer before consuming.  The order in which they do this is not important, so I'm trying to tell each one to take something from the buffer with more in it first, then the other buffer.  I've put a semaphore starting at 3 outside of the consumer code for each buffer.  These are sems upper and lower, and are used to make sure only 3 consumers can enter any one buffer at a time.  </p>
  
  <p>Variables countUpper and countLower are supposed to count how many items are in each buffer at the time.</p>
  
  <p>I'm sure my sems are placed incorrectly but i cannot find out where, I'm very new to threading.  The queues are abstracted and in another file, but they work correctly. Also, I'm only producing lowercase letters atm, but that shouldn't matter. </p>
  
  <p>Any help is appreciated.</p>
  
  <pre><code>#include "pq.h"
  
  #include &lt;stdio.h&gt; 
  #include &lt;stdlib.h&gt; 
  #include &lt;time.h&gt; 
  #include &lt;semaphore.h&gt; 
  #include &lt;pthread.h&gt; 
  
  #define MAX_CPRODUCER 3
  #define MAX_LPRODUCER 3
  #define MAX_CONSUMER 10
  #define MAX_INT 2147483647
  
  // Is the structure for the items produced by the producer thread
  typedef struct product product_t;
  struct product {
    char item;
    int PrdPID;
    unsigned int sequence_num;
  };
  
  typedef struct pq_struct pq_struct_t;
  struct pq_struct
  {
      pq_t lower;
      pq_t upper;    
  };
  
  int countUpper, countLower;
  sem_t mutex, fillCount, emptyCount;
  sem_t mutex2, fillCount2, emptyCount2;
  sem_t lower, upper;
  
  
  //Produce a letter to put in
  product_t *produce(int pid, unsigned int count)
  {   
      product_t *aProduct = malloc( sizeof(*aProduct) );
      aProduct-&gt;item = (char)(rand() % 26 + 97); //To get ascii lowercase
      aProduct-&gt;PrdPID = pid;
      aProduct-&gt;sequence_num = count;
  
      return aProduct;
  }
  
  //Append the letter to the buffer
  void append(void *pq, product_t *aProduct)
  {
      //Insert letter into queue
      //Key is irrelevant and always 1 for this program
      pq_insert((pq_t*)pq, 1, (void*)aProduct);
      //printf("Appended: ID = %d     Count = %d      Letter = %c\n", aProduct-&gt;PrdPID, aProduct-&gt;sequence_num, aProduct-&gt;item);
  }
  
  //Take a letter from buffer
  product_t *take(void *pq)
  {
      //Delete from buffer and place in our consumer product
      product_t *aProduct = (product_t*)pq_delete((pq_t*)pq);
      return aProduct;
  }
  
  //Consume the letter
  void consume(product_t *aProduct, product_t *theProduct, int id)
  {   
      printf("Removing: ID = %d     Count = %d      Letter = %c\n", aProduct-&gt;PrdPID,    aProduct-&gt;sequence_num, aProduct-&gt;item); 
      free(aProduct);  //Takes place of consume
      free(theProduct);
  }
  
  //Producer function for uppercase buffer
  void *ProducerCapital (void *pq) 
  { 
      pq_t *upperPq = pq;
      product_t *cProduct = NULL;
      unsigned int count = 0;
  
       for (;;) 
       { 
          cProduct = produce(1, ++count);
          sem_wait(&amp;emptyCount);
              sem_wait(&amp;mutex);
                  //Make new item
                  append(upperPq, cProduct);
                  ++countUpper;
                  // 
              sem_post(&amp;mutex);
          sem_post(&amp;fillCount);
      }
  pthread_exit (NULL);
  } 
  //Producer thread for lowercase buffer
  void *ProducerLower (void *pq) 
  { 
      pq_t *lowerPq = pq;
      product_t *lProduct = NULL;
      unsigned int count = 0;
  
       for (;;) 
       { 
          lProduct = produce(1, ++count);
          sem_wait(&amp;emptyCount2);
              sem_wait(&amp;mutex2);
                  //Make new item
                  append(lowerPq, lProduct);
                  ++countLower;
                  // 
              sem_post(&amp;mutex2);
          sem_post(&amp;fillCount2);
      }
  pthread_exit (NULL);
  } 
  
  void ConsumeUpper(pq_t *pqUpper, product_t *capProd)
  {
      sem_wait(&amp;fillCount);
             sem_wait(&amp;mutex);
                 //Take Item
                 capProd = (product_t*)take((void*)pqUpper);
                 //    
             sem_post(&amp;mutex);
      sem_post(&amp;emptyCount);
  
  }
  
  void ConsumeLower(pq_t *pqLower, product_t *lowProd)
  {
      sem_wait(&amp;fillCount2);
             sem_wait(&amp;mutex2);
                 //Take Item
                 lowProd = (product_t*)take((void*)pqLower); 
                 //    
             sem_post(&amp;mutex2);
      sem_post(&amp;emptyCount2);
  
  }
  
  void *Consumer (void *pq) 
  { 
       pq_struct_t *sharePqs = (pq_struct_t*)pq;
       product_t *capitalProduct = NULL;
       product_t *lowerProduct = NULL;
  
       for (;;) 
       {  
  
          if(countUpper &lt; countLower)
          {
              sem_wait(&amp;lower);
              --countLower;
              ConsumeLower(&amp;sharePqs-&gt;lower, capitalProduct);
              sem_post(&amp;lower);
  
              sem_wait(&amp;upper);
              --countUpper;
              ConsumeUpper(&amp;sharePqs-&gt;upper, capitalProduct);
              sem_post(&amp;upper);
          }
          else
          {   
              sem_wait(&amp;upper);
              --countUpper;
              ConsumeUpper(&amp;sharePqs-&gt;upper, capitalProduct);
              sem_post(&amp;upper);
  
              sem_wait(&amp;lower);
              --countLower;
              ConsumeLower(&amp;sharePqs-&gt;lower, capitalProduct);
              sem_post(&amp;lower);
          }
  
          consume(capitalProduct, lowerProduct , 2); 
      }
  pthread_exit (NULL);
  } 
  
  int main () 
  { 
      //Create queue
      pq_struct_t my_pqs;
  
      //Initialize the queue
      pq_init(&amp;my_pqs.upper);
      pq_init(&amp;my_pqs.lower);
  
      pthread_t cProducers[MAX_CPRODUCER];
      pthread_t lProducers[MAX_LPRODUCER]; 
      pthread_t consumers[MAX_CONSUMER];
      srand(time(NULL)); // randomize random function call
  
      int i, code; 
  
      countUpper = 0;
      countLower = 0;
      sem_init(&amp;mutex, 0, 1);
      sem_init(&amp;fillCount, 0, 0);
      sem_init(&amp;emptyCount, 0, MAX_INT);
      sem_init(&amp;mutex2, 0, 1);
      sem_init(&amp;fillCount2, 0, 0);
      sem_init(&amp;emptyCount2, 0, MAX_INT);
  
      sem_init(&amp;lower, 0, 3);
      sem_init(&amp;upper, 0, 3);
  
  
      for (i=0; i&lt;MAX_CONSUMER; ++i) 
      { 
         printf ("In main: creating consumer thread %d\n", i); 
         code = pthread_create(&amp;consumers[i], NULL, Consumer, (void *)&amp;my_pqs);
  
         if (code) 
         { 
          printf ("Error: pthread_create: %d\n", code); 
          exit (-1);  
         } 
      }
  
      for (i=0; i&lt;MAX_CPRODUCER; ++i) 
      { 
         printf ("In main: creating producer thread %d\n", i); 
         code = pthread_create(&amp;cProducers[i], NULL, ProducerCapital, (void *)&amp;my_pqs.upper);
  
         if (code) 
         { 
          printf ("Error: pthread_create: %d\n", code); 
          exit (-1);  
         } 
       } 
  
      for (i=0; i&lt;MAX_LPRODUCER; ++i) 
      { 
         printf ("In main: creating producer thread %d\n", i); 
         code = pthread_create(&amp;lProducers[i], NULL, ProducerLower, (void *)&amp;my_pqs.lower);
  
         if (code) 
         { 
          printf ("Error: pthread_create: %d\n", code); 
          exit (-1);  
         } 
       }   
       pthread_exit (NULL);
  } 
  </code></pre>