问题陈述如下:
通常,一组协作线程将在循环中执行一系列步骤 在每个步骤之后在屏障处同步。对于这个应用程序,我们需要一个可重用的 在所有线程都通过后锁定自身的屏障。
鉴于解决方案是:
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()
假设我们将这个屏障用于2个线程,我们通过此屏障泵送100个线程。当第二个线程已解锁旋转门(7)并到达线9时,现在,线程3出现并且,
它递增计数,
计数> n所以它释放互斥,
由于十字转门被解锁,它也达到临界点,
类似地,线程4,线程5,线程6可以执行临界点,执行它超过2次
什么阻止他们穿过线程2前面的障碍?或者我的理解在这里错了吗?
答案 0 :(得分:1)
问题陈述表明(第22页):
您可以假设有n个线程,并且该值存储在a中 变量n,可从所有线程访问。
因此,如果n = 2并且有100个线程,则您违反了此假设,解决方案将无效。
答案 1 :(得分:0)
也许这超出了这个问题,但是这里说:只要最多n个线程在屏障代码内,所列出的解决方案就是我所能说的正确。保证这一点的一种方法是总共只有n个线程。
本书还提供了一种不同的方法来确保只有n个线程位于给定区域内:Multiplex(使用信号量来保证最多n个线程一次使用给定的资源)。像这样使用它:
general_barrier.init(n):
occupancy = Semaphore(n)
barrier = Barrier(n)
general_barrier.enter():
occupancy.wait()
barrier.enter()
barrier.leave()
general_barrier.leave():
occupancy.signal()
您可以这样使用它:
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()
在问题的代码中,您可以在第2行放置occupancy.wait()
,在第24行放置occupancy.signal()
,基本上可以使用此解决方案。请注意,问题中的代码在临界点后面等同于barrier.leave()
,即general_barrier.leave()
,而不是之前的{{1}}。我并不认为这对于正确性很重要,尽管它对于执行的上下文切换次数可能很重要。也许,在某些情况下。建议读者自行决定; - )