CS 439: Project 2
Synchronization - Recursive/Statistical Locks
Due: Friday, Oct. 12th, 11:59PM
This is an individual project. No teaming is allowed.
Overview
Software tuning for large systems often involves an
analysis of lock contention. For this reason, lock implementations often
capture statistical data including the numbers of times the locks were
acquired/release, and the duration of time the lock was held.
In addition, some applications with fine-grained
locking are easier to write if the Thread owning a lock can acquire the lock
any number of times without intervening unlocks (and lose the lock only after
unlocking it the same number of times.)
This is particularly useful when already holding a lock for an instance A of an
item, and then needing to traverse a list of items that may, itself, include A.
If logic requires locking each item on the list, then supporting recursively
locking avoids awkward code.
Purpose
- Understand how to identify
the Thread that is accessing a lock.
- Understand the semantics of
recursive locks.
- Understand how to manage
meta-data associated with a lock.
- Gain familiarity with FIFO
locks (code provided).
- Learn how to use JUnit
testing.
Assignment:
- Complete the provided skeleton implemention of a Recursive,
Statistical Lock (Class name student.RecursiveLock)
using only the locking support provided by cs439.lab2.lock.FIFOLock.
- Run the 5 provided JUnit tests (in cs439.lab2.lock).
- Each Junit test must pass!
- The console output of each test must produce exactly the same output as that test's associated output file (located in the project's outputs directory.)
- Run the Test_Chaos JUnit test on one of the CS Lab's Multiprocessor machines!
Very few points will be awarded to your solution if it doesn't work on an SMP!
Supplies
- project2_cs439.zip in Eclipse importable archive format:
wget http://cs.utexas.edu/~rockhold/CS439/project2/project2_cs439.zip
- Sample outputs for the junit tests
- Test_*.output (one each for the 5 junit tests)
Of the classes provided, the following are the foundations for your
solution:
- The 5 JUnit test cases to test
your implementation of RecursiveLock. These are all in the package,
cs439.lab2.lock.
- cs439.lab2.lock.FIFOLock
provides FIFO semantics, ensuring that the Thread that has waited the
longest for a lock is the one next given the lock. This is done so
that the underlying lock behavior of your RecursiveLock is deterministic. It also
cooperates with ScheduledThread to inform it as its Threads are
blocked/unblocked.
- student.RecursiveLock.java
Contains a skeleton implementation of the methods you're required to complete.
This is the ONLY file you will modify.
RecursiveLock
Your solution (student.RecursiveLock)
must:
- implement all the Interfaces of:
- cs439.lab2.lock.ILock -
methods acquire, acquire_try,
release,
and getName.
Note that these return an int,
rather than a boolean/void.
Read the javadoc comments carefully.
- cs439.lab2.lock.IStatsLock -
includes methods for retrieving statistics about lock usage. Again,
read the doc carefully.
-
implement the public static int getInstanceCount()
method that returns the number of instances of
RecursiveLock that have been
created.
-
allow for recursive locking by the same Thread:
- Once a Thread (ThreadA) has acquired a lock B, later requests by ThreadA
to lock B will succeed immediately.
-
Lock B is only released when ThreadA has released lock B as many times as it
has acquired lock B.
-
conform to the following:
- Must use the provided cs439.lab2.lock.FIFOLock
for any/all synchronization.
-
You are not allowed to use Java
synchronization, except
in RecursvieLock's constructor
-
You may not use any synchronization classes other than FIFOLock.
- pass the 5 JUnit tests
without throwing any exceptions.
Note that you are provided with the sample output for all 5 JUnits tests.
These are provided in the outputs directory. Your results for Test_Chaos may
not match exactly (non-determinism).
- have a constructor that
takes the lock "name" as the only String argument.
- throw a cs439.lab2.lock.LockProtocolViolation
(provided) exception if a Thread that doesn't "own" a lock tries
to release it.
- use static long ScheduledThread.getTime()
whenever you need to determine the current time.
- of course, be
thread-safe.
Testing Your Work - JUnit (Eclipse or Makefile)
Project2 was exported from Eclipse, with a build path that included: /usr/share/java/junit.jar
This should work on the CS Linux machines. If not, then you will need to remove this from the build path (to avoid error messages), and set it up as needed for your system.
You can run the JUnit tests individually (or en masse) within Eclipse. Using Eclipse for debugging a failing test will be extremely useful.
You can/should use the provided Makefile (in the root of the project) to test your solution.
There are five make "targets", one for each of the tests (the make target tests will run all them for you.)
- one_simple_thread
- two_simple_threads
- violation
- instance_count
- chaos
These will run the test, redirecting the output to a file, then, for all tests except chaos, it will diff your captured output with the correct output.
If it runs successfully, you should get an "OK ...test" message from JUnit, and the diff should not report any discrepencies, e.g.:
$ make violation
java -cp ./:/usr/share/java/junit.jar:./bin org.junit.runner.JUnitCore cs439.lab2.lock.Test_Violation 2> Test_Violation.output
JUnit version 4.8.2.
Time: 0.01
OK (1 test) <<<< OK is what you want!
diff Test_Violation.student outputs/Test_Violation.output <<<< and this shouldn't report any differences
$
We will be running these same tests to check your implementation.
Files to turn in
- RecursiveLock.java (Your completed implementation)
- README (provided, but you need to complete)
You need to fill out the README file, including the questions at the bottom.
When you're finished with the project, use the make target:
make turnin
which will create a tar file of your work (README and student/RecursiveLock.java), and invoke turnin for you.
If you'd like to create the tar file and look it over, you can create it without doing the turnin using:
make turnin_setup