1. First compile and execute the distributed program. Note that it deadlocks.
In order to make running it less frustrating, I made it terminate with the
message ``No runnable threads."
2. Modify the program by changing the order of calls to use two-phase locking
and produce a version of the program with modified threads, which doesn't
deadlock. Note that it never terminates, because each thread sits in a rather
pointless infinite loop.
3. Now go back and solve the deadlock problem by modifying the resource management
package, instead of the thread code: Check for deadlock when a thread waits for
a semaphore, and if granting it would cause deadlock, make the thread wait until
things are safe. (In order to check, you'll need to define some new data structures,
and perhaps insert some additional code into each thread to manage them.)