这是sleeping barber problem的解决方案。 (归因于CGrand,但我找到了引用here)
我对dosync
中的enter-the-shop
阻止感到好奇。我的理解是这是一个交易,因此empty-seats
因STM而保持一致。但是,如果重试事务,是否有可能多次调用send-off
?如果没有,为什么,如果是,如何解决它?
更新
虽然接受的答案仍然正确,但我注意到的一件事是可以进行优化 - 没有理由在事务中调用send-off
。一旦获得交易的返回值,就可以发送它,如下所示:
(if (dosync
(when (pos? @empty-seats)
(alter empty-seats dec)))
(send-off barber cut-hair n)
(debug "(s) turning away customer" n))
有趣的是,我在处理Haskell equivalent时想到了这一点,这迫使你在STM内部和STM外部使用不同类型的“代理”。上面的原始解决方案不会编译,因为它们既可以在事务中,也可以在任何事务之外。 (我的第一反应是将它们都放在交易中,直到我意识到不需要这个并且它们都可以被提取出来。)
我认为修改后的交易应该是优越的,因为它可以更快地关闭交易,从交易中删除变量,我认为更容易阅读(甚至不必怀疑它被发送两次的可能性 - 这实际上使整个问题没有实际意义)尽管如此,我还是会留下任何需要知道STM和代理如何互动的人。
答案 0 :(得分:5)
代理与STM集成 - 事务中的任何调度都会一直保留到提交,如果重试或中止,则会被丢弃。
因此send-off
只会在(/ if)成功提交STM事务时运行一次。