从Clojure矢量原子中删除第一个项目并将其返回

Dav*_* J. 10 clojure

我有一个原子包裹物品的矢量:

(def items (atom [1 2 3 4]))
Run Code Online (Sandbox Code Playgroud)

我想原子地删除第一个项目并将其返回.此代码说明了逻辑:

(let [x (first @items)]
  (swap! items #(subvec % 1))
  x)
Run Code Online (Sandbox Code Playgroud)

但是当许多线程相互竞争时,上面的代码是不正确的.阅读和更新之间存在竞争条件.

正如在这个答案中所说的那样,原子用于不协调的同步访问.我希望这可以用原子而不是ref来完成,因为原子更简单.

有没有只使用原子的解决方案,而不是refs?(我将尝试使用手表,看看情况如何.)如果你的答案坚持需要参考,你能否解释一下为什么需要参考,即使建议在需要"协调同步访问许多身份时参考" "(与上述相同的链接).

这与其他相关问题不同,例如如何在Clojure中更新原子的向量元素?在Clojure中删除原子列表中项目的最佳方法,因为我想更新一个向量原子返回该值.

A. *_*ebb 11

旋转环compareAndSet用于swap!原子.Clojure还compare-and-set!为原子提供了较低级别,您可以使用它来执行自己的自旋循环并返回旧值和新值.

(defn swap*!
  "Like swap! but returns a vector of [old-value new-value]"
  [atom f & args]
  (loop [] 
    (let [ov @atom 
          nv (apply f ov args)]
      (if (compare-and-set! atom ov nv)
        [ov nv]
        (recur)))))

(defn remove-first-and-return [atom]
  (let [[ov nv] (swap*! atom subvec 1)]
    (first ov)))
Run Code Online (Sandbox Code Playgroud)

  • @AlexMiller我也这么认为 - 直到我看到[atom.java中的`swap!`源代码](https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ Atom.java#L33)它还依赖于`.compareAndSet`的循环.我现在认为这是对原子的良好运用.为什么要为这个简单的用例烦恼呢? (2认同)