这是作为睡眠理发师问题的解决方案提出的。(归因于CGrand,但我在这里找到了参考)
我很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 等效项时发现了这一点,这迫使您在 STM 内部和 STM 外部使用不同类型的“代理”。上面的原始解决方案无法编译,因为它们必须要么都在事务中,要么都在任何事务之外。(我的第一反应是将它们都放入事务中,直到我意识到没有必要这样做并且它们都可以被提取)。
我认为修改后的事务应该更好,因为它可以更快地关闭事务,从事务中删除一个变量,并且我认为更容易阅读(甚至不需要怀疑它被发送两次的可能性——这实际上使得这整个问题没有实际意义)不过,无论如何,我还是把这个问题留给任何需要了解 STM 和代理如何交互的人。