开发者

Understanding ReusableBarrier Problem (from 'Little Book of Semaphores')

开发者 https://www.devze.com 2023-03-04 06:02 出处:网络
The problem statement is as follows: Often a set of cooperating threads will perform a series of steps in a loop and

The problem statement is as follows:

Often a set of cooperating threads will perform a series of steps in a loop and synchronize at a barrier after each step. For this application we need a reusable barrier that locks itself after all the threads have passed through.

Given Solution is:

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()

Suppose we use this barrier for 2 threads and we pump 100 threads through this barrier. when second thread has unlocked turnstile(7) and reaches line 9, now, thread 3 come along and,

it increments count,

count > n so it releases mutex,

since turnstile is unlocked it reaches critical point also,

similarly, thread 4, thread 5, thread 6 can execute critical 开发者_StackOverflowpoint, executing it more than 2 times.

what is stopping them from passing through the barrier ahead of thread 2? Or is my understanding wrong here?


The problem statement indicates (page 22):

You can assume that there are n threads and that this value is stored in a variable, n, that is accessible from all threads.

So if n=2 and there are 100 threads, you have violated this assumption and the solution will not work.


Maybe this goes beyond the question, but here goes: the listed solution is as far as I can tell correct as long as at most n threads are inside the barrier code. One way of guaranteeing this is to only have n threads in total.

The book also presents a different way of ensuring that only n threads are inside a given region: the Multiplex (using a Semaphore to guarantee that at most n threads use a given resource at a time). Use it like this:

general_barrier.init(n):
    occupancy = Semaphore(n)
    barrier = Barrier(n)
general_barrier.enter():
    occupancy.wait()
    barrier.enter()
    barrier.leave()
general_barrier.leave():
    occupancy.signal()

You would use it like this:

shared state:
    gbarrier = general_barrier(n)
each of m threads (where m > n, but in particular try m > 2*n):
    while True:
        gbarrier.enter()
        something critical
        gbarrier.leave()

In the code in the question, you could put occupancy.wait() on line 2 and occupancy.signal() on line 24, and have basically this solution. Note that the code in the question puts the equivalent of barrier.leave() after the critical point, i.e. in general_barrier.leave(), rather than before as I have done it. I don't think this matters for correctness, though it may matter in regards to the number of context switches performed. Maybe, in some situations. Reader discretion is advised ;-)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号