This commentary page描述了GHC中STM
的许多细节,但我想澄清几点。
第一次,是否在父项中访问的变量发生更改时,嵌套事务无效?
例如我们在线程A
:
takeTMVar a `orElse` takeTMVar b `orElse` takeTMVar c
假设在A
执行嵌套事务takeTMVar b
时,另一个线程B
执行putTMVar a ()
;可以线程A
成功完成其嵌套事务,还是无效(这会让我觉得错误)?
第二点,我认为我理解但不介意再保证:在上面针对A
描述的整个顶级事务被重试并最终阻止的情况下,如果A
,a
或b
中的任何一个发生变化,c
会被唤醒是否正确?
最后作为奖励,如果我们(或图书馆作者)将orElse
更改为infixr
,上述交易的语义是否会发生变化?
答案 0 :(得分:5)
我不认为“嵌套”是描述这一点的正确术语。这是三个备用交易; none嵌套在另一个中。特别是,三者中的任何一个都将发生并被提交 - 但是哪一个发生并不是确定性的。这句话应该足以回答所有三个问题,但为了确保,让我们仔细说出每个问题:
无法保证。也许takeTMVar b
将完成并提交;或者它可能会被抢占,takeTMVar a
将被唤醒并完成。但他们不会同时完成,这是肯定的。
是的,这是正确的:所有三个TMVar
都可以唤醒这个帖子。
语义不会改变:只要其中几个可以提交,最左边的那个就会。 (特别是,the paper describing STM说,“orElse
函数遵循有用的法则:它是关联的,并且具有单位retry
。”。)
(来自评论中的问题)链接文件第8页上STM的语义确实可以保证最左边成功的事务 成功的事务。所以:如果线程A
正在执行takeTMVar b
(但尚未提交)并且线程B
执行并提交写入a
,那么之后不会发生任何其他事情,您可以确定将重新启动线程A
并从a
返回新写入的值。 “之后没有其他事情发生”部分很重要:语义对发生的事情作出承诺,而不是实现如何实现它;因此,如果另一个线程立即从a
获取(以便takeTMvar a
仍然是retry
),则允许一个足够聪明的实现注意到这一点,而不是重新启动线程{{ 1}}从交易开始。