猴子过桥问题的试解
2012年9月1日
猴子过桥问题的试解
猴子过桥问题是操作系统课本上的一个同步问题,见于塔嫩鲍姆的操作系统设计与实现第二版。今天是2012年8月15日,而昨天晚上我躺在床上睡觉时,想到了这个问题的一个答案。
问题概述:在两个相对的悬崖间,有一根绳子。悬崖两边有许多猴子,分别要到对面去。其中有一些属性,比如不能让不同方向的猴子同时处于绳上,同一方向的猴子必须依次通过等等。问,如何使用同步原语解决这个问题?
为了解决这个问题,我想到了以下的模型:一个表示当前方向的整数direction(0表示没有猴子在绳上,1表示猴子向右爬,2表示向左),一个表示当前方向上有几只猴子的整数count,一个用于保护前面两个变量的互斥量mutex。绳子上的步骤可以有多步,每一步都用一个独立的信号量step_semaphore[i]表示它是否有猴子在爬,总的步数step_count,一个通知当前方向的猴子是否已全部爬过的信号量rope_semaphore。(我一开始的想法里面有些东西没弄对,比如,想用两个信号量,分别控制两个方向。)
算法概述:
{
第一个猴子上绳:
down(mutex)
if direction == 0:
# first monkey
direction = self.direction
count = 1
down(step_semaphore[0]) # for now nobody has occupied the rope
# if someone downed step_semaphore[0], it must have changed `direction'
down(rope_semaphore)
self.step = 0
up(mutex)
elif direction == self.direction:
...
else:
...
第二个或后续猴子上绳:
down(mutex)
if direction == 0:
...
elif direction == self.direction:
# followup monkey
count += 1
up(mutex)
# not the first one so step_semaphore[0] can cause deadlock if downed
# before upping mutex
# QUESTIONS: 1. if all ahead ones quit; a: it won't up rope_semaphore; 2.
# if more monkeys come; a: they'll compete on step_semaphore, which will be
# judged by the OS
down(step_semaphore[0])
self.step = 0
else:
...
反方向猴子想要上绳:
while True:
down(mutex)
if direction == 0:
...
elif direction == self.direction:
...
else:
# opposite direction monkey
up(mutex)
# QUESTIONS: 1. if all other direction ones quit; a: it will get
# rope_semaphore; 2. if more monkeys come; a: they'll compete first on
# rope_semaphore, then on mutex, which will be judged by the OS
down(rope_semaphore)
up(rope_semaphore)
# now loop back to try again; note that we can't down mutex before the
# up because doing this would break the lock order, which may lead to
# dead lock
正方向猴子完成一步工作:
do_work()
if self.step + 1 < step_count:
# it doesn't make much sense to up the semaphore without downing the next,
# and that may even lead to wrong order
down(step_semaphore[self.step + 1])
up(step_semaphore[self.step])
self.step += 1
else:
# quit the rope
down(mutex)
# the up for step_semaphore is safe here
up(step_semaphore[self.step])
count -= 1
if count == 0:
direction = 0
up(rope_semaphore)
up(mutex)
self.step = -1
}
规律总结:所有连续的down操作,只要能在检查mutex所保护的变量后保证马上成功,都在mutex信号量down的时候进行。所有不能保证马上获得的信号量则除外。所有down操作,只要之前有过up操作的,都要考虑此过程中是否有别的线程插入的情况,并将其抽象为一些同类状态,想办法合并多次操作后的状态为其中的一类,还要考虑嵌套的插入情况。