This lab was developed by CSCI 315 staff and modified by Prof. L. Felipe Perrone. Permission to reuse this material in parts or in its entirety is granted provided that this credits note is not removed. Additional files associated with this lab, as well as any existing solutions can be provided upon request by e-mail to perrone[at]bucknell[dot]edu
In your git repo, create a directory for today’s lab called Lab6. In this directory, create a file called lab6.txt, where you’ll write answers in text for some of the problems in this lab.
It goes without saying that you need to create a Makefile instrumented to build each and every one of the executables in this lab. Failing to do that will lose you 10 points for the lab.
The standard statement of Dining Philosophers is a resource allocation problem. As in the version for pre-lab problem, it consists of five philosophers sitting around a table and cycling through the states thinking, getting hungry, and eating.
Philosophers need chopsticks in order to eat. Between each pair of philosophers, there lies one single chopstick. When a philosopher wants to eat, s/he must acquire two chopsticks; that is, s/he must try to get exclusive access to the chopstick on the left and also to the one on the right. Effectively, this means that no two neighboring philosophers can ever eat at the same time. A complicating factor is that when a philosopher want to eat, s/he must request each chopstick separately, that is, one at a time.
For this problem, you will create a program called problem1.c, which implements your solution to the dining philosophers problem. In this program, you will use the mutex and semaphore constructs, which you have used before. Each chopstick must be modeled by a mutex and each philosopher by a thread.
The Philosopher threads request chopsticks by doing two successive locks: one for the chopstick on the left and one for chopstick on the right. Once a Philosopher passes through the wait on a mutex, it is assumed to have picked up the corresponding chopstick. Since a Philosopher must pick up both the left and the right chopsticks in order to be able to eat, you can think of the “eating” section as the critical section of the Philosopher‘s code.
Your implementation must follow the guidelines below, which are consistent with the solution in the SGG textbook:
Your solution to this week’s pre-lab may have been created to pass into each Philosopher thread a philosopher’s numeric id as a parameter to the thread function. This will allow the creator of the threads to assign the id of each thread when it invokes pthread_create for each individual philosopher. If your solution did not already incorporate this tactic, you should modify it before you start on this lab. When each philosopher knows its id, the messages it will print can include that id value and therefore you will be able to distinguish which messages come from which philosopher.
Compile and run the resulting program.
./problem1 > problem1.out
Hint: When you look at your problem1.out file, you might not see any output. If that is the case, think about whether you are using buffered output. It could be that your program is writing to output buffers that are not being flushed and when you kill the program with Ctrl-C, the file turns out to be empty. Remember that you can force the buffers to be flushed in your program, which will avoid this issue.
By submitting your output file, you earn (4 points). Not submitting this file can potentially compromise the grader’s ability to assess your solutions, so don’t take any chances.
Create a file lab6.txt in which you will include answers to the following questions:
1.1 Run your code for about 10 seconds. Do you observe any problems when your program runs? Report what you observe. (3 points)
1.2 Based on your understanding of the code, how could deadlock possibly happen? (Hint: reason through all the four conditions to deadlock occurrence and explain if they all apply.) (3 points)
When you are done with this, you need to:
The standard solution for dining philosopher can potentially run into deadlock. In this problem, you will try to simulate deadlock to verify first-hand what happens.
Look closely at the code in problem1.c and identify where deadlock might occur. Keep in mind that deadlock is not so much related to some static sequence of statements in the code; it is due to the manifestation of a sequence of events observed at run time.
Copy your program problem1.c, to a new file called problem2.c. Remember the napping() function you created for your prelab assignment? In your Philosopher function, add calls to napping() to try to encourage deadlock to occur. Feel free to modify the list of arguments of your napping() function as you see fit, but add comments to the function explaining what each parameter is for. Some students, for instance, have chosen to pass into napping() a pointer to the variable that stores the random number generator seed for the specific thread that is calling this function.
Experiment with where to insert these calls and also with the lengths of naps until you do observe deadlock in your test runs. (12 points)
So that you can see the behavior of Philosophers at run time, after each pthread_mutex_lock call, add a message saying:
“Philosopher i picking up chopstick j”
Similarly, after each pthread_mutex_unlock, add a message saying:
“Philosopher i putting down chopstick j”
Note: Once you can cause deadlock to happen, it’s a good idea to run the program again a number of times to see if the behavior might change. With good choices of when to nap and of the length of naps, you will see that sometimes your program deadlocks quickly and sometimes it will run for a while without deadlocking. This will serve as proof that deadlock is the result of a particular sequence of events: having the potential for deadlock in your code is not a guarantee that it will occur. The non-deterministic nature of deadlock occurrence can make debugging really difficult.
When your program runs into deadlock, save its execution to a file called problem2.out. You can do this with cutting and pasting the output to a file, or alternatively, take your chances and use I/O redirection (just make sure that the file you generate does show deadlock!)
2.1 Your submission of the program’s output earns you (4 points). Not submitting this file could potentially compromise the grader’s ability to assess your solutions, so don’t take any chances.
In your file lab6.txt, include the answer to the following question:
2.2 Describe the situation you observed which lead to deadlock. (4 points)
When you are done with this, you need to:
If the behavior of Philosphers is perfectly symmetrical, it is quite likely that you will observe deadlock. In general, symmetric behavior occurs when similar threads consistently make the same choices. While in some cases this isn’t a problem, in other cases it will lead to deadlock.
Problems with symmetrical behavior are common in computer science. Parallel algorithms where multiple processes or threads act on a set of common resources tend to exhibit this kind of behavior. For this reason, it is important to develop strategies to break symmetry.
In parallel algorithms, a common technique is to apply randomness at the point of symmetry. For example, individual processes can each flip a coin (or the computational equivalent), then decide what to do based on the result. We could do this in the Dining Philosophers solution, and greatly decrease the probability of deadlock occurrence. (In this case, each Philosopher thread could sample a random number to decide which chopstick to pick up first.) Unfortunately, the use of randomness only reduces the probability of symmetric behavior; it does not eliminate it altogether. We need to be extra careful with the possibility of deadlock.
One way to break symmetry in the Dining Philosophers is to make different Philosopher threads behave differently. There are a couple of obvious possibilities:
In both of the new implementations above, make sure to leave in the napping() calls that produced the deadlock in your Problem 2 solution. Compile and run each of your solutions until you convince yourself that they run without deadlocking.
In your file lab6.txt, include the answer to the following question:
3.1 Discuss whether these solutions eliminate all the potential causes of deadlock. If you conclude that they don’t, indicate what problem(s) can still occur. (4 points)
When you are done with this, you need to:
Before turning in your work for grading, create a text file in your Lab 7 directory called submission.txt. In this file, provide a list to indicate to the grader, problem by problem, if you completed the problem and whether it works to specification. Wrap everything up by turning in this file: