MC78 Lab 1: Races and Monitors (Fall 1996)
Due: September 24, 1996
Goals of the lab
In this lab you (and a partner) will read and understand a
client/server pair of programs written in Java, each of which involves
concurrency. Each program has a race condition, which you must find,
that could lead the program not to behave correctly if the timing of
the threads worked out just wrong. You will write a description of
specifically what could go wrong and under what circumstance. Then
you will empirically verify your predictions by introducing time
delays into the programs at the appropriate points so as to transform
the races from being a problem only under unlucky circumstances into
being easily triggered, and you will document the buggy behavior
exhibited. Finally, you will fix the problems using Java's monitors
feature, by adding the necessary "synchronized" keyword to the
appropriate methods and verifying that this indeed made the buggy behavior
go away.
The programs
This lab involves three Java programs: Flip, NetFlip, and FlipServer.
The Flip program is a single-player non-networked puzzle program that
doesn't involve any concurrency issues. It isn't really part of the
lab proper, but is the basis for the NetFlip program, which is simply
a multi-user networked version of Flip in which all the users are
playing together on a single puzzle: they can all see the same board
and can all manipulate it. The way this is accomplished is that the
various NetFlip games on the net are all tied together by
communication with a single FlipServer. The hostname of the computer
that the FlipServer is running on needs to be given as a command line
parameter to the NetFlip program.
Java source files
The Flip program is contained entirely in the Flip.java source file,
which defines a single class, Flip, in the
EDU.gac.max.flip package.
The NetFlip program re-uses that same source file and adds a
NetFlip.java source file,
which defines two classes, NetFlip and
NetInterface,
both of which are again in the EDU.gac.max.flip package.
(The package these classes are in implies that the files should be in
a directory EDU/gac/max/flip.)
The FlipServer program is contained in the source file FlipServer.java,
which defines two classes, FlipServer and
ClientConnectionThread,
both in the EDU.gac.max.flipserver package. In addition, the
FlipServer program makes use of a library class (in addition to the
standard Java libraries), MulticastOutputStream,
from the EDU.gac.max.io package. The source for that class is in MulticastOutputStream.java,
but you can safely treat this class as a black box. In particular, it
is thread-safe (all its methods are synchronized), so its internal
details play no role in the race conditions.
How to compile and run Java programs
To use Java, you'll need
to add /usr/local/java/bin to your search path. You can do this using
the command set path=(/usr/local/java/bin $path). Once you
have done that, you can compile a java program by, for example, saying
javac EDU/gac/max/flip/Flip.java. Note that the Flip.java
file needs to be down four levels deep in subdirectories to correspond
to the Java package EDU.gac.max.flip that it is in. To run the
program, you can then say java EDU.gac.max.flip.Flip. Note
that the command line argument to the java interpreter is the name of
the class, not the filename. For a program such as NetFlip that
expects an additional command line argument of its own (the hostname
of the FlipServer), you would use a command like java
EDU.gac.max.flifp.NetFlip localhost. (The hostname
localhost is a special name that always refers to the
machine you are on, regardless of which machine you are on. This will
be handy for most of the lab, though at points you may want try
sharing a FlipServer with one or more teams on other machines.) You
can run any of these programs in the background by putting a
& at the end of the command line, so that your shell is
available for issuing other commands from. That way you can start a
FlipServer and as many NetFlips as you want all from one shell.
How to insert a time delay
To insert a time delay, say of
five seconds, into a program at some point, just insert the following
Java statement: try{Thread.sleep(5000);}catch(Exception
e){}
. This sleeps for 5000 milliseconds (i.e., 5 seconds), and
if an exception occurs (such as would be caused if the sleep were
explicitly interrupted), ignores it.
What to turn in
Turn in a jointly-authored lab report containing the following
information:
- an analysis of the race condition in the NetFlip program: what can
go wrong, and under what circumstance?
- a similar analysis of the race condition in the FlipServer program
- a description of how you verified these races using inserted
sleeps; what did you do and what was the (buggy) result?
- a statement of which methods needed to be "synchronized" to fix
the problem
Instructor: Max Hailperin