睡眠理发师问题:如何避免理发师在顾客就绪前开始理发?
睡眠理发师问题中信号量时序疑问的解答
我近期在研究经典的睡眠理发师问题,从维基百科上找到一个可行的解决方案:
# The first two are mutexes (only 0 or 1 possible) Semaphore barberReady = 0 Semaphore accessWRSeats = 1 # if 1, the number of seats in the waiting room can be incremented or decremented Semaphore custReady = 0 # the number of customers currently in the waiting room, ready to be served int numberOfFreeWRSeats = N # total number of seats in the waiting room def Barber(): while True: # Run in an infinite loop. wait(custReady) # Try to acquire a customer - if none is available, go to sleep. wait(accessWRSeats) # Awake - try to get access to modify # of available seats, otherwise sleep. numberOfFreeWRSeats += 1 # One waiting room chair becomes free. signal(barberReady) # I am ready to cut. signal(accessWRSeats) # Don't need the lock on the chairs anymore. # (Cut hair here.) def Customer(): while True: # Run in an infinite loop to simulate multiple customers. wait(accessWRSeats) # Try to get access to the waiting room chairs. if numberOfFreeWRSeats > 0: # If there are any free seats: numberOfFreeWRSeats -= 1 # sit down in a chair signal(custReady) # notify the barber, who's waiting until there is a customer signal(accessWRSeats) # don't need to lock the chairs anymore wait(barberReady) # wait until the barber is ready # (Have hair cut here.) else: # otherwise, there are no free seats; tough luck -- signal(accessWRSeats) # but don't forget to release the lock on the seats! # (Leave without a haircut.)
起初该方案看似合理,但我发现一个潜在漏洞:根据我对信号量的有限理解,signal()可以在对应的wait()之前执行。假设理发师执行signal(barberReady)后立即开始理发,而此时顾客还未执行wait(barberReady),这在逻辑上不合理,因为顾客尚未就绪。请问操作系统(或信号量语义)如何防止这种不匹配情况?
其实你担心的这种“时序不匹配”不会导致逻辑问题,核心在于信号量的计数特性:
- 信号量本质是带等待队列的计数器。当
signal()先于wait()调用时,信号量的计数会先加1;后续wait()调用时,会直接消耗这个已有的计数,不会阻塞。 - 回到这个场景:理发师只有在
wait(custReady)成功后(确认有顾客等待),才会执行signal(barberReady)。这意味着这个signal()必然对应某个已经坐下的顾客——哪怕顾客还没走到wait(barberReady)这一步,信号量的计数会把“理发师就绪”的通知暂存起来。等顾客后续调用wait(barberReady)时,会直接取用这个计数,进入理发环节。 - 从数量匹配上看:每一个
signal(custReady)对应一个wait(custReady),每一个signal(barberReady)对应一个wait(barberReady),两者的调用是严格一一对应的,不会出现“理发师白理发”或者“顾客永远等不到”的情况。
简单来说,信号量的计数机制天然解决了“通知提前到达”的问题,它相当于把通知暂存起来,等需要的线程来取,既不会丢失也不会乱序。
内容的提问来源于stack exchange,提问作者CN.hitori
相关产品推荐
相关产品推荐

