ABA与Clojure软件事务内存
我想知道Clojure是否有ABA问题的内置解决方案。 我正在创建一个示例来说明这个问题,但Clojure不知怎么检测到了这些变化。这是因为Clojure的事务比较引用而不是值吗 我的例子是:ABA与Clojure软件事务内存,clojure,transactions,stm,aba,Clojure,Transactions,Stm,Aba,我想知道Clojure是否有ABA问题的内置解决方案。 我正在创建一个示例来说明这个问题,但Clojure不知怎么检测到了这些变化。这是因为Clojure的事务比较引用而不是值吗 我的例子是: (def x (ref 42)) (def io (atom false)) (def tries (atom 0)) (def t1 (Thread. (fn [] (dosync (commute x - 42))))) (def t2 (Thread. (fn [] (dosync
(def x (ref 42))
(def io (atom false))
(def tries (atom 0))
(def t1 (Thread. (fn [] (dosync (commute x - 42)))))
(def t2 (Thread. (fn [] (dosync
(Thread/sleep 100)
(commute x + 42)))))
(def t3 (Thread.
(fn []
(dosync
(do
(Thread/sleep 1000)
(swap! tries inc)
(if (= 42 @x)
(reset! io true)))))))
(.start t3)
(.start t1)
(.start t2)
(.join t1)
@x
(.join t2)
@x
(.join t3)
@tries
(if (= true @io) (println "The answer is " @x))
trys计数始终为2,因此事务t3必须注意到t1和t2的ref变化。有人知道这种行为的原因吗?您是正确的,这是预期的行为(尽管我预期
trys
为1)。除了许多讨论软件事务性内存(STM)的Clojure书籍外,您可能还想回顾一下
此外,通常最好使用
alter
而不是communion
,这很容易出错,通常是“过早优化”的情况。在回答手头的问题之前,我只想说,到目前为止,关于Clojure的STM的最好的信息来源——除了源代码本身——我所知道的是Mark Volkmann的文章(链接指向changelog页面,然后从那里链接到最新版本)。它非常全面。(不要担心2009年的时间戳,STM没有太大变化。)如果你想仔细思考在这样的场景中事情是如何工作的,我强烈建议你阅读它
至于目前的情况: 对于Ref的事务内读取,STM承诺返回在当前事务尝试之前提交的值。(当然,除非当前事务try本身设置了相关Ref的事务内值。)该值可能是也可能不是写入Ref的最新值,但如果不是,则需要从Ref的历史记录中满足读取要求。如果Ref的历史记录不包含此类值,则会记录Ref的故障并重试事务。随后,由于故障,Ref历史链的长度可能会增加,直到Ref的最大历史长度(默认为10),但请注意,只有在有机会(对Ref的另一次写入)的情况下,才会发生这种情况,并且只对“足够晚”启动的事务有帮助(因此它们的时间戳晚于历史记录中某些值的时间戳) 在本例中,当
t3
开始读取Ref时,t1
和t2
将完成对x
的写入,没有任何问题,x
将不再能够满足从t3
第一次尝试之前要求值的读取请求。(这是因为Ref的历史链默认从长度0开始,这意味着没有保留历史值。)因此t3
必须记录x
的故障,然后重试
(如果您针对相同的Ref和helper原子重新运行这三个事务,例如,通过将除前三行之外的所有行再次粘贴到REPL中,您将看到trys
在第二次运行时跳到4
,然后在第三次运行时跳到5
,表明此时有一个历史值可用。)
关于ABA问题: ABA问题与STM无关,因为在适当的ABA场景中,“B”由不同的线程写入内存位置(1),(2)在“主”线程第一次读取“a”之后(即意味着出现ABA问题的线程),然后类似地,第二个“a”由不同的线程写入(1),(2)在主线程观察到“B”写入和两个“a”,但“B”不是——但如上所述,在STM事务中,您无法在事务尝试启动后观察到其他线程写入Ref的值,因此如果观察到第一个“a”,您将无法观察到“B”或第二个“a”
这并不意味着STM不可能出现与并发相关的问题–很容易出现写倾斜(如中所述–这是
sure
函数设计用来解决的问题,但在适当的情况下由用户代码调用它),通勤
可能被误用&c.好的,我现在明白了。问题是我读到的一些资料表明ABA是STM的一个问题。