Each exercise this quarter is rated on a integer scale of 1 – 5, inclusive, with 1 being the "least time-consuming" and 5 being the "most time-consuming".
This difficulty scale is meant as a rough guide for you in predicting the amount of time to set aside for each exercise as you balance the work required for 333 with your other obligations. However, it is necessarily imperfect as everyone's set of circumstances and experiences with the exercises differ. If your experience with an exercise does not align with its rating, that is not a reflection of you or your abilities.
pthreads.A common design pattern used in concurrent programming is the . In this design pattern, there is a set of producers that generate work for a set of consumers. As the producers create work items, they place them into a buffer/queue. When a consumer is free to process a new work item, it will grab the next one from the buffer/queue or wait if the buffer/queue is empty.
In this exercise, you will take an initial sequential producer-consumer program and change it so the producers and consumer run concurrently. To make things more interesting, the producers will produce (пиріжки: we are using the romanization with an 's' and not a 'z') and (налисники), which are popular foods in Ukraine, and the consumers will be responsible for eating them!
The initial program will:
Since this code runs sequentially, all of the piroshki are produced first, followed by all of the nalysnyky, and then all the snacks are eaten in the order in which they were produced.
Your job is to make the two producers and the consumer tasks run
concurrently using pthreads and NOT C++11 threads.
When the producers and consumer are run concurrently, the output of
the program should change.
For example, instead of all the snacks being made first and then
all eaten, some piroshki could be made, a few could be eaten, and
then a nalysnyky could be made and immediately eaten.
Each producer should create its snacks and add them to the queue as
they are created.
The consumer should remove snacks from the queue and eat them.
If no snacks are present in the queue when the consumer is ready to
eat another one, it should wait a short while and then check again
to see if a new snack is available.
We have provided you with the following four source files, which can be downloaded from or with the commands:
$ wget https://courses.cs.washington.edu/courses/cse333/26sp/exercises/ex12_files/<filename>
SimpleQueue.h — Contains the class
definition for SimpleQueue, a linked list queue that
is used as the producer-consumer buffer and is currently NOT
thread-safe!SimpleQueue.cc — Contains a working
implementation of SimpleQueue that is NOT currently
thread-safe.ex12.cc — Contains the given producer
and consumer functions plus the initial, sequential
main code.Makefile — Provided for your
convenience in compiling the executable ex12.SimpleQueue.h,
SimpleQueue.cc, and ex12.cc
so you should not modify the Makefile.
pthread Library
You may find the following functions useful when writing your
program:
pthread_create,
pthread_exit,
pthread_join,
pthread_mutex_init,
pthread_mutex_destroy,
pthread_mutex_lock, and
pthread_mutex_unlock.
In addition, you should understand the
,
because it could be necessary for making our const
methods thread-safe.
In order for the producers and consumers to run concurrently
without stepping on each others' toes, you will need to make
SimpleQueue thread-safe by modifying it so it acquires
a lock when it runs critical sections of code and releases it when
the critical section finishes.
A critical section of code is any section where a modifiable
resource shared among threads is accessed.
If critical sections are not protected by locks, bad things such as
data races and data structure corruption can occur.
You should use a pthread mutex for this part.
Once SimpleQueue is thread-safe, you should change
ex12.cc so that the producers and consumer run
concurrently using pthreads.
You should NOT modify the given producer or consumer functions.
Instead, you should start threads with new wrapper functions that
call the desired producer/consumer function.
For this exercise, "thread-safe" code means that it is synchronized with respect to accessing data. However, there may be inconsistencies with the usage of that data after we have read it. For example, it is possible with a thread-safe implementation to have a consumer print that they have consumed a snack before the producer has a chance to print that it has been produced. This behavior is OK for this exercise, as long as you make sure that the accessing of the shared data is thread-safe.
You should not change most of the starter code.
You should only change what is necessary to make the program
multithreaded and thread-safe.
This means you may not change which methods are declared
const in SimpleQueue.
In the case of an error, be sure to release all resources, especially when working with locks.
Submit the following file(s) by creating an ex12-submit tag in your exercise repo before the assignment deadline. The file(s) should be located in the exact directory listed below (there should be a folder titled ex12 with ex12.cc, SimpleQueue.h, and SimpleQueue.cc within that folder), including capitalization:
ex12/ex12.ccex12/SimpleQueue.hex12/SimpleQueue.ccOther files in the ex12 folder will be ignored, so you may keep the files unnecessary for submission in there!
For full credit, your code must:
attu, or CSE home VM).g++ and valgrind)..cc and
.h files with your name(s) and CSE or UW email
address(es).cpplint.py).