Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ABA与Clojure软件事务内存_Clojure_Transactions_Stm_Aba - Fatal编程技术网

ABA与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

我想知道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 
                          (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的一个问题。