Discussion questions: monitors

Please work out these problems before your next discussion section. The GSIs and IAs will go over these problems during the discussion section.

1. Restroom access

U-M decides to save money on the construction of the new CSE building by building only unisex restrooms (as opposed to redundant men's and women's rooms on each floor). For modesty's sake, however, they impose the rule that only people of one gender may occupy a given restroom at the same time.

Your task is to write a program which models access to a restroom, using Mesa monitor primitives.

Write the following procedures: woman_wants_to_enter(), man_wants_to_enter(), woman_leaves(), man_leaves().

Use the monitor primitives lock(), unlock(), signal(), wait(), and broadcast() in these functions to control access to the restroom. You may assume there is no limit on the number of people of the same gender who may occupy the restroom at a given time.

Next, we want to modify our solution in order to prevent starvation. In other words, a person should not have to wait indefinitely to enter, assuming that each person already in the restroom stays there for some finite time period. We will try to ensure fairness using a bool called TURN. TURN can be set to either MEN or WOMEN. Write a solution that uses the TURN variable to alternate priorities between men and women when both groups are waiting. For example, if there are women in the bathroom and men waiting for the bathroom and a woman arrives, the woman should only be allowed in if TURN = WOMEN. Flip the TURN variable when appropriate.

Notice that we can change the TURN variable in either the woman_leaves() function, or the woman_wants_to_enter() function.

  1. Describe the fairness policy enforced if we change the TURN variable in woman_wants_to_enter().
  2. Describe the fairness policy enforced if we change the TURN variable in woman_leaves().
  3. Do either of these actually prevent starvation?
We want a policy that maximizes concurrency while not allowing for starvation. What fairness policy do we actually want? What would it take to implement this?

2. Locks

Assume n threads are accessing m independent shared objects (e.g., shared variables). How many locks are required to provide maximum concurrency within the threads? Does more concurrency imply better performance?

3. File access

Several threads are accessing a file. Each thread has a a unique priority number. The file can be accessed simultaneously by several threads, subject to the following constraint: the sum of all unique priority numbers of the threads currently accessing the file must be less than n.

Show how to use monitors to coordinate access to the file.

4. Barriers

(This problem has optional background material. The background reading tries to give you a sense of how you might find parallelism and use monitors in a real world problem, and attempts to motivate the usefulness of barriers. If you'd like to read the background material, click here. It is not necessary to understand the background material to do the problem.)

A barrier is a tool that provides a way for various threads to synchronize their progress. Threads "check in" or wait at a barrier and are only allowed to proceed past the barrier when a certain number of threads have "checked in" to the barrier. This tool allows a program to run phases in parallel (particularly useful in matrix operations).

Your job is to implement barriers using monitors. Implement the constructor and wait function adding private variables as needed.

class Barrier {
  //Add your private member variables

  /* Constructs a new barrier that will allow number_of_threads
     threads to check in. */
  Barrier(int number_of_threads);

  /* Called by a thread checking in to the barrier. Should return
     true if the thread was the last thread to check in (in POSIX threads
     lingo, the "serial thread") and false otherwise. This function should
     block until all threads have checked in. */
  bool wait();

  /* Delete copy constructor and copy assignment operators */
  Barrier(const Barrier&) = delete;
  Barrier& operator=(const Barrier&) = delete;
  Barrier(Barrier&&) = delete;
  Barrier& operator=(Barrier&&) = delete;