You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

睡眠理发师问题:如何避免理发师在顾客就绪前开始理发?

睡眠理发师问题中信号量时序疑问的解答

我近期在研究经典的睡眠理发师问题,从维基百科上找到一个可行的解决方案:

# 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 12:12:21