1. Develop a pseudocode solution
Come up with a pseudocode solution to synchronize the actions of Producer and Consumer threads that add (produce) and remove (consume) items using a shared, fixed-capacity buffer:
-
Some number of Producer threads, each in a loop forever:
-
produce the next item
-
add it to the shared buffer (to one end of a circular queue)
-
-
Some number of Consumer threads, each in a loop forever:
-
remove the next item from the shared buffer
-
consume it
-
1.1. 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?
1.2. Starting point assumptions
-
You may assume the following shared global buffer state.
static char *buff; // the buffer static int N; // total capacity static int size; // current num elements static int next_in; // next insertion index static int next_out; // next remove index static int num_items; // number of items each thread should produce/consume -
There exist functions to add items to and remove items from the buffer (implemented as a circular queue).
void add_to_queue(char item); char remove_from_queue();These functions have no synchronization, and they do not check to see if there is space to add an item or if there is an item that can be removed. They just add to or remove from the buffer in a circular fashion and update other state variables as a result of their actions. This means you need to prevent adding to an already full buffer or trying to remove an item from the buffer that doesn’t exist, but you should prevent this without modifying those functions.
-
Some
pthreadfunctions:pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex); pthread_cond_wait(&mycond, &mutex); pthread_cond_signal(&mycond); pthread_barrier_init(&mybarrier, NULL, num_threads); pthread_barrier_wait(&mybarrier); -
When you are happy with your pseudo-code algorithm talk your algorithm through with the professor or ninja. before moving on to the next step.
2. Implement your Pseudocode Solution
Try implementing your algorithm in pthreads. You can do
this on paper first, which might be the preferred first
step for implementing.
You can also try implementing and testing it using some
starting point code and a Makefile
that you can copy from here:
$ cd ~/cs31/
$ mkdir -p inclass/w13
$ cd inclass/w13
$ cp -r ~newhall/public/cs31/inclass/w13/* .
$ ls
Makefile prodcons.c
$ make
$ ./prodcons 8 100 10
8 prods/cons, each produces/consumes 100 items, buff size 10
Note that to functions to add and remove items from the circular
buffer, and a print_buffer function is provided. Whenever you print,
you should call fflush(stdout) to force debugging information
to the terminal window.
-
Implement code in
mainto spawn producer and consumer threads. -
Implement the
producerandconsumermain loop functions. -
Add all synchronization necessary to synchronize the actions of concurrent producer and consumer threads.
-
Look at the
manpages forpthreadfunctions:$ man pthread_create $ man pthread_join $ man pthread_cond_init $ man pthread_mutex_init -
Look at the weekly lab page for other
pthreadexamples.
-