In the solution we present in class, we use two mutex variables. Many of the solutions submitted use one mutex only. A question raised during discussion with a student whether any solution with one mutex is wrong.
I will post some of the solutions submitted by you, and let you take a look and discuss. I think debugging threads is not easy and is a skill that comes with experience. So hopefully this little exercise will serve as a practice for you.
First, I will start off with the correct solution (labelled A) using two mutex variables. The mutex s ensures that only one savage waits at one time.
VERSION A mutex s, m cond filled, empty savage: while (true) lock(s) lock(m) if (pot is empty) signal(empty) wait(filled, m) eat() unlock(m) unlock(s) cook: while (true) lock(m) if (pot is not empty) wait(empty, m) cook() signal(filled) unlock(m)
Before we move on to implementations that uses one mutex, here is a slight variable of the above. Here, locking and unlocking of m is done inside the if statement. Is it correct?
VERSION B mutex s, m cond filled, empty savage: while (true) lock(s) if (pot is empty) lock(m) < -- signal(empty) wait(filled, m) unlock(m) <-- eat() unlock(s) cook: while (true) lock(m) if (pot is not empty) wait(empty, m) cook() signal(filled) unlock(m)
Now, here are the four versions of solutions that uses only one mutex.
Version C removes the use of mutex s.
VERSION C mutex m cond filled, empty savage: while (true) lock(m) if (pot is empty) signal(empty) wait(filled, m) eat() unlock(m) cook: while (true) lock(m) if (pot is not empty) wait(empty, m) cook() signal(filled) unlock(m)
Version D replaces signal(filled) with broadcast(filled) in the cook thread.
VERSION D mutex m cond filled, empty savage: while (true) lock(m) if (pot is empty) signal(empty) wait(filled, m) eat() unlock(m) cook: while (true) lock(m) if (pot is not empty) wait(empty, m) cook() broadcast(filled) < -- unlock(m)
Version E added a signal(filled) after eat() to VERSION C.
VERSION E mutex m cond filled, empty savage: while (true) lock(m) if (pot is empty) signal(empty) wait(filled, m) eat() signal(filled) < -- unlock(m) cook: while (true) lock(m) if (pot is not empty) wait(empty, m) cook() signal(filled) unlock(m)
Version F changes the if statement to while statement.
VERSION F mutex m cond filled, empty savage: while (true) lock(m) while (pot is empty) < -- signal(empty) wait(filled, m) eat() signal(filled) unlock(m) cook: while (true) lock(m) if (pot is not empty) wait(empty, m) cook() signal(filled) unlock(m)