Haskell 与orElse嵌套的STM事务中的验证
在GHC中描述了许多关于Haskell 与orElse嵌套的STM事务中的验证,haskell,concurrency,ghc,stm,Haskell,Concurrency,Ghc,Stm,在GHC中描述了许多关于STM的详细信息,但我想澄清几点 首先,当父事务中访问的变量发生更改时,嵌套事务是否无效 例如,我们在线程中有一个: takeTMVar a `orElse` takeTMVar b `orElse` takeTMVar c 假设A正在执行嵌套事务takeTMVar b,另一个线程b执行putTMVar A();线程A能否成功完成其嵌套事务,或者它是否已失效(我认为这是错误的) 第二点,我想我理解,但我不介意再次保证:如果上面描述的A的整个顶级事务被重试并最终阻塞,那么
STM
的详细信息,但我想澄清几点
首先,当父事务中访问的变量发生更改时,嵌套事务是否无效
例如,我们在线程中有一个:
takeTMVar a `orElse` takeTMVar b `orElse` takeTMVar c
假设A
正在执行嵌套事务takeTMVar b
,另一个线程b
执行putTMVar A()
;线程A
能否成功完成其嵌套事务,或者它是否已失效(我认为这是错误的)
第二点,我想我理解,但我不介意再次保证:如果上面描述的A
的整个顶级事务被重试并最终阻塞,那么当A
、b
或c
中的任何一个发生更改时,A
将被唤醒,这是否正确
最后,如果我们(或库作者)将orElse
更改为infixr
?我不认为“嵌套”是描述这一点的正确术语,那么上述事务的语义是否会发生更改。这是三种替代交易;没有一个嵌套在另一个中。特别是,这三种情况中有一种将要发生并被实施——但哪种情况发生并不确定。这一句话应该足以回答所有三个问题,但可以肯定的是,让我们仔细地对每一个问题说:
没有保证。可能takeTMVar b
将完成并提交;或者它可能会被抢先,并且takeTMVar a
将被唤醒并完成。但它们不会同时完成,这是肯定的
是的,这是正确的:所有三个TMVar
s都可以唤醒这个线程
语义不会改变:只要其中几个可以提交,最左边的一个就会提交。(特别是说,“orElse
函数遵循有用的规则:它是关联的,具有单元重试
”。)
(从你在评论中的问题来看)链接文章第8页的STM语义确实保证了最左边成功的交易就是成功的交易。因此:如果线程A
正在执行takeTMVar b
(但尚未提交),并且线程b
执行并提交对A
的写入,并且之后没有发生任何其他事情,则可以确保线程A
将重新启动并从A
返回新写入的值。“之后什么也不发生”部分很重要:语义承诺发生什么,但不承诺实现如何实现它;因此,如果,比如说,另一个线程立即从a
中获取(因此takeTMvar a
仍将进行重试
),那么一个足够聪明的实现可以注意到这一点,而不会从事务开始重新启动线程a
我可能不明白你的第一点;明确地说,我使用的TMVar
只是我能想到的第一个例子,这是一个简单的事务,其中包含retry
(即,take和put的具体交互以及什么调用retry并不重要)。在我的第一个问题中,我真正想了解的是,在不同的TVars
上运行的不同线程中,子事务之间是否存在争用。如果这不合理,我会在吃了东西后再澄清链接评论中使用的语言也是嵌套的哦,我明白你的意思了!因此,我知道只有一个orElse
分支会成功;我想知道在A
中,在我们从第一个分支继续之后,另一个线程(B
)是否可以通过触摸我们在第一个分支中使用的TVar
使A
事务无效branch@jberryman我添加了一些文本。希望这次我能理解你的问题。谢谢你,丹尼尔。在最后一点上,我不得不写一个痛苦的测试程序来说服自己,但这似乎是正确的。我仍在试图把我的头绕在它周围,但这在我看来确实是一种错误的行为:orElse
的左分支和右分支拥有相同的世界观有什么好处,因为它们之间是完全孤立的?我认为,将分支单独作为原子将是一个更有用的特性。就像现在一样,通过编写一些orElse
s,就很容易挨饿。思想?