Quiz 1 Answers ============== PROBLEM 1 --------- The Java Language Specification states, in Section 17.8.1, entitled "Wait", the following: "If thread t is interrupted, an InterruptedException is thrown and t's interruption status is set to false." In Section 17.8.3 entitled "Interruptions" it states: "Let t be the thread invoking u.interrupt, for some thread u, where t and u may be the same. This action causes u's interruption status to be set to true." One says the status is set to false while the other says its set to true. Explain why this is not inconsistent. Answer: It's true that whenever one calls t.interrupt() then the interrupt status of t is set to true. The sentence in 17.8.1 talks about what happens when a thread has called wait(). While the thread t is in the middle of executing wait(), another thread's invocation of t.interrupt() will set the interrupt status to true, but the thread is still in the middle of executing wait(). The code that implements wait() detects the change to true, and then does the following: it gets out of the wait set, resets the interrupt status to false, and then throws an InterruptedException. So even in the former case the status goes to true, but only fleetingly; the implementation of wait() resets it right away. PROBLEM 2 --------- Here's a piece of a solar system simulation. It's a class for planets that revolve around a sun. Each planet is a thread whose run() method continuously updates its current position along a circular path of radius r. A separate thread runs along periodically drawing all of the planets by calling getPosition() for each. There's something wrong here. Explain what could happen here and also show how to fix the problem. class Planet extends Thread { private double r, u, x, y, du; public Planet(double r, double du) {this.r=r; this.du=du; x=r; y=u=0;} public void run() {while (true) {u+=du; x=r*cos(u); y=r*sin(u);}} public Point getPosition() {return new Point(x, y);} } Answer: Other threads will be calling getPosition() while this thread is running, and they can read a point with a new x position and an old y position. The simplest fix is to introduce critical sections, remembering to keep the lock scope as small as possible. class Planet extends Thread { private double r, u, x, y, du; public Planet(double r, double du) { this.r=r; this.du=du; x=r; y=u=0; } public void run() { while (true) { u+=du; synchronized (this) { x=r*cos(u); y=r*sin(u); } } } public synchronized Point getPosition() { return new Point(x, y); } } PROBLEM 3 --------- >Prove or disprove that a Dining Philosophers solution that permits only four philosophers to be seated at any given time is deadlock-free. Assume philosophers pick up their right chopstick first and then their left, blocking indefinitely to obtain each one. Answer: The solution is free of deadlock. Assume that the system is deadlocked. Then all philosopher threads are deadlocked. Therefore the philosopher sitting to the left of the empty seat is blocked. But that thread is not blocked waiting for the right chopstick since the seat to the right is empty. Therefore it is blocked waiting for the left chopstick. Therefore the left neighbor is holding that chopstick, and since the system is deadlocked, it must be blocked waiting for its left chopstick. By a similar argument the next two philosophers are blocked waiting for their left chopstick. But the last such philosopher cannot be blocked waiting for its left chopstick because the seat to its left is empty. Therefore we have a contradiction. The system is not deadlocked. PROBLEM 4 --------- What's wrong with the following attempt to enforce mutual exclusion, besides the fact that it polls? After all, it doesn't deadlock and starvation is impossible. Here "turn" is a global variable initialized to 1.
    thread1:                           thread2:
      while (true) {                     while (true) {
        NON_CRITICAL_SECTION_1             NON_CRITICAL_SECTION_2
        while (turn != 1);                 while (turn != 2);
        CRITICAL_SECTION_1                 CRITICAL_SECTION_2
        turn = 2;                          turn = 1;
      }                                  }

Answer:

The system does not meet all the criteria for mutual exclusion:
the two threads are forced into lock-step execution of their
critical sections.

PROBLEM 5
---------

Show how to implement a trivial count down latch with a Semaphore
in Java.  That is, fill in the body of this class:

public class MySemaphoreBasedCountDown {
    Semaphore s;
    ...
    public MySemaphoreBasedCountDown(int count) {...}
    public void await() throws InterruptedException {...}
    public void countDown() {...}
}

Make objects of your class work like Java CountDownLatches, meaning
you can only use them once.

Answer (from A. Carasso):

The trick is to require an acquiring thread to get n permits,
where n is the value of the count down latch.  The semaphore
starts with 0 permits, and each count down increments this count.
When n releases have occurred, one of the waiting threads is
allowed to go.  It grabs the n permits its wants but then puts
them back for any other waiting thread.  All threads from now on
can get their n permits (and put them back).

public class MySemaphoreBasedCountDown {
    Semaphore s = new Semaphore(0);
    public MySemaphoreBasedCountDown(int count) {
        if (count <= 0) {
            throw new IllegalArgumentException("Positive count required");
        }
        this.count = count;
    }
    public void await() throws InterruptedException {
        s.acquire(count);
        s.release(count);
    }
    public void countDown() {
        s.release();
    }
}

An alternate solution initializes the semaphore with a negative
count and tracks the number of count down calls, but I think
this solution is flawed and requires manual synchronization:

public class MySemaphoreBasedCountDown {
    Semaphore s;
    public MySemaphoreBasedCountDown(int count) {
        if (count <= 0) {
            throw new IllegalArgumentException("Positive count required");
        }
        Semaphore s = new Semaphore(-count);
        this.count = count;
    }
    public void await() throws InterruptedException {
        if (count == 0) return;
        s.acquire();
    }
    public void countDown() {
        if (count == 0) return;
        count++;
        s.release();
    }
}