CS 4414 Lab 5: Programming with Pthreads and Semaphores
Due 10pm Weds, 3/28
Introduction
pthreads and semaphores
For this assignment, we will be using POSIX threads (pthreads). Although some of the examples and libraries we provide are in C++, the code you write for this assignment should stick with C.
A great tutorial on pthreads can be found here: http://www.llnl.gov/computing/tutorials/pthreads/
We will also be using the POSIX semaphore library. For this, the man
page should suffice:
man sem_init
[getting information about semaphores]
And an example:
#include <semaphore.h>
int main(int argc, char** argv) {
sem_t mySemaphore;
int pshared = 0;
int initialValue = 5;
if (sem_init(&mySemaphore, pshared, initialValue)) {
switch(errno) {
case EINVAL:
fprintf(stderr, "Error: %d out of range for intial value",
initialValue);
break;
case ENOSYS:
fprintf(stderr,
"Error: LinxThreads does not support process-shared semaphores");
break;
default:
fprintf(stderr,
"Unkown Error Code: %d", errno);
break;
}
exit(errno);
}
return 0;
}
[example code for initializing a semaphore]
Linking
If you use pthreads or POSIX semaphores in your code, you must link
against the pthread library by adding -lpthread to the compiler options when linking.
gcc semaphore_test.cc -lpthread -o semaphore_test
[how to link with the pthread library]
Synchronization
Ch. 6 of Silberschatz et al.
discusses inter-process communication and synchronization.
Submission
Please put your code in your cs4414/lab5 directory in your labunix accounts, and then on Collab submit to confirm the path where we can find your code and the name of your partner. Your documentation and discussion will go in README files that accompany your solutions to each problem.
Submit no later than
10:00pm on Wednesday, 3/28.
Warmup Problem i - Producer / Consumer
We have a bounded LIFO buffer (a fixed-size stack) that is initially
empty. We then create two threads: the producer, whose job is to write as much as it
can to the buffer, and the consumer,
whose job is to read as much as it can from the end of the buffer.
There is nothing to submit for this problem, as we have given you two
solutions to it in prodcon.zip. One of the
solutions uses semaphores and the other
uses condition variables.
Note: if running this messes up your console's colors, just
type reset and then clear.
Play around with these to make sure that you understand the
synchronization concepts. It's always nice to start with working
code. Some things to consider:
- What are the limitations (if any) of each method?
- What changes would you have to make in order to accommodate more
than one producer or consumer?
Warmup Problem ii - H2O
You've just been hired by Mother Nature to help her out with the
chemical reaction to form water, which she doesn't seem to be able to
get right due to synchronization problems. The trick is to get two H
atoms and one O atom all together at the same time. The atoms are
threads. Each H atom invokes a procedure H() when it's ready
to react, and each O atom invokes a procedure O() when it's
ready. For this problem, you are to write the code for H()
and O() (and of course, all the other code to make your
program work). The procedures must delay until there are
two H atoms and one O atom present. When this happens, all three
threads must print out a message saying that Water has been created,
and then exit. You may use either semaphores or locks and condition
variables for synchronization, but avoid starvation and busy waiting
There is nothing to submit for this problem, as we have given you a
semaphores solution to it in h2o.zip. This solution is probably not the most
elegant solution, and is by far not the only solution. If you come up
with a better solution, or one that uses condition variables, please
email the TA's with it.
Problem 1 - Dining Philosophers
As in the classic problem, there are n philosophers sitting around a table, and they only
have n chopsticks, placed evenly between them. Each philosopher
follows the exact same steps:
do forever {
THINK for a while
get HUNGRY
pickup left chopstick
pickup right chopstick
EAT
put down left chopstick
put down right chopstick
}
[pseudo-code for philosopher]
Details
We have provided skeleton code for you in philosophers.zip with a naive
implementation of this algorithm. It is your task to implement this
algorithm, free of deadlocks and starvation.
Hint: most of your code
will go in philosopher_thread()
Please also note that it is better to turn in a solution that works, even if it may suffer from starvation, rather than nothing at all.
Pseudocode solutions to this problem, using both semaphores and
monitors, have been given in class.
You must use mutexes and
condition variables
for your solution. Also, each philosopher must execute the exact same
algorithm (no asymmetric solutions). The philosopher's id is
only to be used for debugging purposes, and may not be part of the
solution.
philosophers_stats
You will also notice that we have provided philosophers_stats.cc for you. This program
will take the output from the philosophers program, and calculate some
simple statistics from it. Feel free to modify this program in any way
- it is not part of the submission, but rather a utility program to
help you debug and test your code. Just be sure that your final
solution runs with the version we're giving you.
./philosophers 5 0.5 1 > out.txt
./philosophers_stats out.txt
[running philosophers_stats on a file]
(try ./philosophers 5 0.1 1 | tee out.txt)
./philosophers 5 0.5 1 | ./philosophers_stats -o
[piping the output of philosophers
directly to philosophers_stats,
and also showing the output to stdout (-o)]
What To Submit
You should submit all the source files necessary to compile philosophers (including the Makefile - make
sure that a single Makefile covers all the code you submit). In
your README file, include any compilation
instructions, a brief description of your philosopher algorithm, an explanation for why it is deadlock and starvation free, and
anything else you would like us to know.
Finally, note that our skeleton code provides a drop-in replacement for printf, called LOCKED_PRINTF, that acquires a mutex for stdout, calls printf, flushes stdout, and releases the mutex, to avoid garbled output from concurrent threads.
Problem 2 - Matchmaker
In what has become another idiosyncratic classic computer science synchronization problem,
you have been hired by an environmental agency to help improve the whale population. Because
unscrupulous commercial interests have dangerously lowered the whale
population, whales are having synchronization problems in finding a
mate. The trick is that in order to have children, three whales
are needed, one male, one female, and one to play matchmaker -
literally, to push the other two whales together (the truth of this claim is
unsubstantiated as far as we know). Your job is to write the two procedures Male() and
Female(). Each whale is represented by
a separate thread. A male whale calls Male(), which will either
act as a matchmaker or wait for a female and a matchmaker. A female
acts similarly.
Details
Your implementation for this problem must use Semaphores. You may also find it useful to
have a mutex for critical
sections. Printing to the console should be part of a critical
section.
We have provided skeleton code in whales.zip.
When whales mate, they leave the problem (they no longer participate in mating or matchmaking).
When a new whale is created, if it can act as a matchmaker (i.e., a male and female are already waiting), it must do
so, but if a matchmaker is not needed at this time, it should wait for a mate. And once it starts waiting for a mate, it should no longer act
as a matchmaker. For whales that serve as a matchmaker, after completing a match, they should check again to see if a matchmaker is needed.
For example, consider the following scenario:
(t=1.0) 0: Female Created
(t=2.0) 1: Female Created
(t=3.0) 2: Male Created
(t=3.0) 0: Found Mate
(t=3.0) 2: Found Mate
Here Whales 0 and 2 have found mates and need a matchmaker. It
would make sense for Whale 1 to now act as a matchmaker, but
because she arrived before Whale 2 and already started waiting for a male, she cannot act as a matchmaker,
leaving Whales 0 and 2 still waiting for a matchmaker to appear.
[whales example]
What To Submit
You should submit all the source files necessary to compile whales (make sure your Makefile covers all
programs you submit). In
your README file, include any compilation
instructions, a brief description of your Male and Female algorithms,
an explanation for why it is deadlock and starvation free,
and anything else you would like us to know.
This skeleton code also provides LOCKED_PRINTF.
The whale problem is courtesy of Sang Son.
Copyright Kevin Skadron, 2005, 2006, 2008.
Last revised Mar. 20, 2012.