CS31 in-class: Pthreads Producer Consumer

Producer-Consumer Bounded Buffer Problem
In your group you are going to do the following:
  1. On paper, come up with a PSEUDOCODE solution to synchronize the actions of Producer and Consumer threads that add and remove items to a shared, fixed-capacity buffer:
    • Some number of Producer threads, each in a loop forever:
      1. produce the next item
      2. add it to the shared buffer (to one end of a circular queue)
    • Some number of Consumer threads, each in a loop forever:
      1. remove the next item from the front of the buffer
      2. consume it

    Some questions to consider:

    • are there actions that need to be made atomic (require mutually exclusive access)?
    • are there any scheduling types of synchronization necessary?
    • what synchronization primitives do you need? and how are they used (by whom and when)?
    • is any other state needed to synchronize the actions of threads?

    You may assume:

    • The following shared global buffer state has been declared:
        static char *buff;     // the buffer
        static int  N;         // total buffer capacity
        static int  size;      // current num items in the buffer
        static int  next_in;   // next insertion index in the buffer 
        static int  next_out;  // next remove index in the buffer
        static int  num_items; // number of items each tid should produce or consume
      
    • There exist functions to add and remove items to the buffer as a circular queue (add to one end, remove from the other).
        void add_to_queue(char item);
        char remove_from_queue();
      
      These functions have no synchronization, nor do they check if there is space on an add or something to remove on a remove. They just add or remove to buff in a circular fashion and update other state variables as a result of their actions.

    • Some pthread functions:
      pthread_mutex_lock(&mutex); 
      pthread_mutex_unlock(&mutex); 
      pthread_cond_wait(&mycond, &mutex); 
      pthread_cond_signal(&mycond); 
      pthread_barrier_init(&mybarrier, NULL, numtids); 
      pthread_barrier_wait(&mybarrier); 
      

    When you are happy with your pseudocode algorithm talk a professor or ninja through your algorithm BEFORE MOVING ON TO THE NEXT STEP.

  2. Next, on paper implement your solution for the producer and consumer threads. First show declarations and initialization for any syncrhonization variables needed. Then write the main part of the code for two thread main functions: one for producer threads and one for consumer threads. If it helps you can copy over the code from the next step, but write up your solution on paper first (you can skip some details that may be needed in a full implementation).

     


  3. Finally, you can try implementing your solution in a pthreads program, and test it out. Copy over starting point pthread code:
     
    cd cs31/inclass 
    cp -r ~newhall/public/cs31/inclass/prodcons  .
    cd prodcons 
    make
    ./prodcons 8 100 10
    8 Producer and Consmer tids, each producing 100 items, buff size 10
    
    There are already routines to add and remove items from the circular buffer, and a debug print_buffer function (call fflush(stdout) after any debug output to force it to the terminal window).
    1. Implement code in main to spawn producer and consumer tids
    2. Implement the producer and consumer main loop functions
    3. Add all synchronization necessary to synchronize the actions of concurrent producer and consumer threads

    Look at the man pages for pthread functions:

    man pthread_create
    man pthread_join
    man pthread_cond_init
    man pthread_mutex_init
    

  4. Before the end of class, share your joint solution with your team mates. Here is one way to do this from the cs machine you are ssh'ed into:
    % mail username1 < prodcons.c
    % mail username2 < prodcons.c