Clojure stm 中的竞争条件?

Race condition in Clojure stm?

你好,我正在阅读《joy of clojure》一书,在关于 STM 的部分中,他们有一个 2 个事务的图像,其中 A 最初从 ref 中检索与 B 相同的值,然后事务 A 和 B 都执行他们的计算,但 A 先完成并提交变量,因此 B 必须重试。

但是我在考虑的是 B 是否会重试 A 的提交。如果是这样的话,那么如果相反呢?那么最终的价值就会有很大的不同。

这似乎是一个被忽视的危险,我相信我没有完全理解它。请帮我解开这个问题。

我们来看例子:

(defn test-trans []
  (let [x (ref 1)
        t-inc #(dosync (alter x inc))
        t-mul #(dosync (alter x (partial * 2)))
        fns (flatten (repeat 10 [t-mul t-inc]))]
    (last (pmap (fn [f] (f)) fns))
    @x))

这里我们有 2 个事务函数 - 将 x 增加 1,将 x 乘以 2。我们并行应用 20 个这样的函数(每种 10 个)并观察 [= 的最终值15=]。每个 运行:

的结果确实不同
=> (test-trans)
2418
=> (test-trans)
2380
=> (test-trans)
1804
=> (test-trans)
4210

实际上这是正确的行为。 STM 保证代码将在没有锁定的情况下执行,并且以原子方式应用更改(它们不能仅部分应用)。但是不保证我们对不同的交易顺序会有相同的结果。

Clojure 提供了很好的并行编程工具,可以大大简化正确代码的编写。但是避免这种竞争条件是开发人员的责任(事实上,这种情况是系统设计不良的明显标志)。

来自 SQL 的另一个示例:

DELETE FROM tbl WHERE col=1
UPDATE tbl SET col=2 WHERE col=1

如果这些查询是并行执行的,那么无论事务使用何种隔离级别 - 结果都将取决于顺序。