3

I have been reading "The Little Book of Semaphores" and in page 41 there is a solution for the Reusable Barrier problem. The problem I have is why it won't generate a deadlock situation.

1 # rendezvous
2
3 mutex.wait()
4     count += 1
5     if count == n:
6         turnstile2.wait() # lock the second
7         turnstile.signal() # unlock the first
8 mutex.signal()
9
10 turnstile.wait() # first turnstile
11 turnstile.signal()
12
13 # critical point
14
15 mutex.wait()
16     count -= 1
17     if count == 0:
18         turnstile.wait() # lock the first
19         turnstile2.signal() # unlock the second
20 mutex.signal()
21
22 turnstile2.wait() # second turnstile
23 turnstile2.signal()

In this solution, between lines 15 and 20, isn't it a bad habit to call wait() on a semaphore (in line 18) while holding a mutex which causes a deadlock? Please explain. Thank you.

casperOne
  • 73,706
  • 19
  • 184
  • 253
kasper360
  • 367
  • 2
  • 4
  • 14

1 Answers1

4

mutex protects the count variable. The first mutex lock is concerned with incrementing the counter to account for each thread, and the last thread to enter (if count == n) locks the second tunstile in preparation of leaving (see below) and releases the waiting (n-1) threads (that are waiting on line 10). Then each signals to the next.

The second mutex lock works similarly to the first, but decrements count (same mutext protects it). The last thread to enter the mutex block locks turnstile to prepare for the next batch entring (see above) and releases the (n-1) thread waiting on line 22. Then each thread signals to the next.

Thus turnstile coordinates the entries to the critical point, while turnstile2 coordinates the exit from it.

There could be no deadlock: by the time the (last) thread gets to line 18, turnstile is guarantted to be not held by any other thread (they are all waiting on line 22). Similarly with turnstile2

Attila
  • 28,265
  • 3
  • 46
  • 55
  • Thank you @Attila. Your answer clearly explains what `turnstile` and `turnstile2` are doing in the code. But in line 18, isn't the last thread gets blocked as it calls wait on turnstile? If that happens, there is no way for `turnstile2.signal()` to be executed, hence creating a deadlock situation. – kasper360 Apr 16 '12 at 11:05
  • 1
    line 7 signaled `turnstile`, so calling wait on it cannot block (assuming of course, only this code manipulates the turnstiles) – Attila Apr 16 '12 at 11:13
  • Thanks a lot @Attila, I have counted the number of `turnstile.signal()` calls wrong. – kasper360 Apr 16 '12 at 12:44
  • I agree with @kasper360 - i've been dry-running this pseudocode with a friend with N=2. We have also reached the same conclusion that when P1 is waiting on line 22 (turnstile2.wait), P2 comes at line 15, decreases the count, enters the IF condition and then waits on the turnstile (line 18). Now P2 cannot move further on turnstile BECAUSE turnstile = semaphore(0) and P1 cannot move further because P1 has already locked turnstile2 because turnstile2 = semaphore(1). Need further clarification Attila. Can you explain it once more? :) – Ali Haider Jan 13 '17 at 19:17
  • @Venomal: I'm not sure why you are confused. First of all, once all threads are past line 11, there is no hold on `turnstile` (so the next `turnstile.wait()` (on line 18) is non-blocking) -- the last thread past line 11 released its own hold on `turnstile`. So in your setup when P1 is waiting on `turnstile2` (line 22), P2 will not be stuck on `turnstile` – Attila Jan 20 '17 at 14:28