这个clojure解决方案是否有睡眠理发师的错误?

Dax*_*ohl 4 clojure stm

这是睡眠理发师问题的解决方案.(归功于CGrand,但我在这里找到了参考)

从cgrand猛拉

我很好奇这个dosync街区enter-the-shop.我的理解是这是一个交易,因此empty-seats将因STM而保持一致.但是,send-off如果重试事务,是否有可能被多次调用?如果没有,为什么,如果是,如何解决它?

UPDATE

虽然接受的答案仍然是正确的,但我注意到的一件事是可以进行优化 - 没有理由send-off在交易中调用.一旦您拥有交易的返回值,就可以在事后发送,如下所示:

(if (dosync
       (when (pos? @empty-seats)
         (alter empty-seats dec)))
    (send-off barber cut-hair n)
    (debug "(s) turning away customer" n))
Run Code Online (Sandbox Code Playgroud)

有趣的是,我在处理Haskell等效时想出了这个,这迫使你在STM和STM之外的"代理"中使用不同的类型.上面的原始解决方案不会编译,因为它们既可以在事务中,也可以在任何事务之外.(我的第一反应是将它们都放在交易中,直到我意识到不需要这个并且它们都可以被提取出来).

我认为修改后的事务应该是优越的,因为它可以更快地关闭事务,从事务中删除变量,我认为更容易阅读(甚至不必怀疑它被发送两次的可能性 - 这实际上是这整个问题没有实际意义)尽管如此,我仍然会提出任何需要了解STM和代理如何互动的人.

man*_*nge 5

在代理商上引用clojure.org页面:

代理与STM集成 - 在事务中进行的任何调度都会保留,直到它提交为止,如果重试或中止,则会被丢弃.

因此,send-off只有当(/ if)STM事务成功提交时,才会运行一次.