UNIVERSITY OF WISCONSIN-MADISON
Computer Sciences Department
CS 537
Spring 1998
Program #2

Using Monitors to Save Your Life

Due: Mar 17 by 1pm

Introduction

You are to write the code to provide the synchronization to control access to a collection of pedestrian bridges. The bridges are used to cross a dangerous, shark-infested river. The picture below illustrates the problem.

Bridges

Specification

We have written for you a class called Bridges. This class has the following methods that you can call. (More detailed documentation is also available).

There are also methods Bridges.toString() and Bridges.verbose(int verbosity) provided to help you with debugging.

Each person is a thread running a Person class, which you must write, that implements the following interface (see also the complete specification.)

Your Person class may also contain any additional methods that you need.

Use a ``monitor'' (a Java class with synchronized methods) as the synchronization mechanism for your solution. Create an instance of the monitor in the main() method and save it as a static field of the ``main'' class so that it can be easily referenced from Person.run().

Your solution must obey the following rules:

  1. Each bridge is strong enough to hold only capacity persons at a time, where capacity is a parameter to the Bridges constructor. Additional people will break the bridge and they all will fall in the river and drown.
  2. Bridges are one-way. If two people try to cross the same bridge in opposite directions at the same time, they will fall into the river.
  3. If there is more than one person wanting to cross the river, as many bridges as possible should be in use at the same time.
  4. Initially, all the bridges are unoccupied.

If you violate the above rules or call the Bridges methods incorrectly, the people will fall in the river and drown (actually, an exception will be thrown, either Drowning or IllegalArgumentException ).

You must prepare two solutions to this problem. In the first solution, there is no fairness guarantees. There is a separate waiting line for each bridge. A newly arriving person gets in the shortest waiting line and waits for a chance to cross that bridge. However, there is no alternation guarantees for people wanting to go in both directions. If some people are going east on one bridge, newcomers going east can get onto the bridge as long as the capacity is not exceeded, even if there are already people waiting to go west on the bridge. Thus, in this solution, people waiting at either the east or the west end of the bridge may be starved to death (since there is no fast-food place at either end of the bridges).

In the second solution, people on both sides cross the bridge based on the First-Come-First-Cross discipline. You can assume that people never arrive at the opposite ends of the bridge at exactly the same time.

Which solution gives better performance in terms of average waiting time?

Compiling and Running

Create a new directory for this project. You will need to define at least three classes for this project, the ``main'' class, the class Person, and a monitor class. Put the source for each class in a separate .java file (with the same name as the class). Copy the implementation of the Bridges and Drowning classes to your working directory.

    cp /p/course/cs537-cao/public/project2/*.class .
Then compile and run your program as usual.
    javac Project2.java
    time java Project2
The word ``time'' at the beginning of the second command causes Unix to print a message after the command completes indicating how much CPU time you used. This will give a hint how efficient your solution is (see below).

More details on tests you should run will be posted before the due date.

Hints

For the first solution, you could use a separate instance of a monitor for the waiting line of each bridge. Each time a person finished crossing a bridge, he would call notifyAll, waking up the people waiting at either end of the bridge. Each one would check whether it would be safe for him to cross, and go back to sleep otherwise.

For the second solution, you will need a monitor class to coordinate access to the bridges. We'll call it CrossingGuard for this discussion. This class will have to keep track of the state of all the bridges (how many people are currently crossing each bridge and which way they are going). There is no way of getting this information directly from Bridges. (There is a toString method, but that's just for debugging.) CrossingGuard will have a method a person calls when he wants to cross the river.

You should not call Bridges.cross() from a synchronized method of CrossingGuard. If you do so, everything may seem to work fine, but you will get terrible performance. When a thread gets blocked in Bridges.cross(), it will still be holding the monitor lock for CrossingGuard, preventing any other thread from entering any method of CrossingGuard. The result will be that only one person will cross the river at a time, regardless of how many bridges there are and regardless how many people each bridge can hold. Instead, you should have two synchronized methods, one that blocks the caller until it is safe to call Bridges.cross() and the other to be called after Bridges.cross() returns.