开发者

Threadsafe pop in clojure?

开发者 https://www.devze.com 2023-02-27 12:47 出处:网络
I\'ve found this code on http://www.learningclojure.com/2010/11/yet-another-way-to-write-factorial.html, but I don\'t understand if/how the pop-t开发者_如何学JAVAask is supposed to be threadsafe. Does

I've found this code on http://www.learningclojure.com/2010/11/yet-another-way-to-write-factorial.html, but I don't understand if/how the pop-t开发者_如何学JAVAask is supposed to be threadsafe. Doesn't it allow to return twice the same head ?

(def to-do-list (atom '()))  
(defn add-task![t] (swap! to-do-list #(cons t %)))  
(defn pop-task![] (let [h (first @to-do-list)] (swap! to-do-list rest) h))

If so, is it possible to keep using atom and write the peek and swap! atomically, or is this a job for the ref mechanism ?


Or you drop to a lower level.

(def to-do-list (atom nil))

(defn add-task!
   [t]
   (swap! to-do-list conj t))

(defn pop-task!
   []
   (let [[h & r :as l] @to-do-list]
     (if (compare-and-set! to-do-list l r)
       h
       (recur))))


Yeah, that code isn't thread safe. You can make it thread-safe by taking advantage of the fact that swap! returns the new value of the atom, which implies you need to combine the queue with the "popped" value.

(def to-do-list
  (atom {}))

(defn add-task!
  [t]
  (swap! to-do-list
         (fn [tl]
           {:queue (cons t (:queue tl))})))

(defn pop-task!
  []
  (let [tl (swap! to-do-list
                  (fn [old]
                    {:val (first (:queue old))
                     :queue (rest (:queue old))}))]
    (:val tl)))
0

精彩评论

暂无评论...
验证码 换一张
取 消