Danger! What won't work
Even though Clojure gives you great data structures and primitives, it won't save you from coding race conditions. Check out these examples which won't work:
;; WILL NOT WORK (def queue (atom '(:foo :bar :baz :qux))) ;; the code below is called from threads ;; take the first value of the "queue", derefing it (let [peeked-val (first @queue)] (do-something-with peeked-val) ;; update the atom to remove the first value ;; DANGER: You've derefed the value above but you're swapping it in a separate step ;; (here). Other threads may have read the same value or may have mutated it ;; in the meantime! (swap! queue rest))
What about refs?
;; WILL NOT WORK (def queue (ref '(:foo :bar :baz :qux))) ;; the code below is called from threads ;; take the first value of the "queue", derefing it, this time in a transaction! (dosync (let [peeked-val (first @queue)] (do-something-with peeked-val) ;; update the ref to remove the first value in the transaction ;; DANGER: Refs give you transactional consistency (i.e. consistency ;; between read/write access to other refs) but this doesn't really apply ;; here as we only have on ref. Other threads may have read the same value ;; or may have mutated it in the meantime! (alter queue rest)))
Solve it in Clojure
You can accomplish this with Clojure's data structures and atoms. The key is to use swap-vals! so you only touch the atom once - otherwise you'll run into race conditions as you have two operations as in the example above: Derefing the atom (getting its value) and swapping it (changing its value).
(def queue (atom '(:foo :bar :baz :qux))) ;; use `swap-vals!` on atoms to get both the old and new values of the atom. ;; perfect if you want to peek (get the first value) while doing a pop (removing ;; the first value from the atom, thereby mutating it) ;; use the code below in threads (or somewhere in core.async) ;; it's somewhat non-idiomatic to use `rest` and `first`, see the text below for ;; other options (let [[old new] (swap-vals! queue rest)] (println "here's the popped value:" (first old)))
You could also use a PersistentQueue instead, construct it with (clojure.lang.PersistentQueue/EMPTY) - then you can call peek and pop on it instead of first and rest. Don't forget to put it in an atom just like the list above :)
Use Java Data Structures
You could also use something like a java.util.concurrent.LinkedBlockingDeque. Check out this commit which introduces parallel building capabilities to the ClojureScript compiler for an example of using a LinkedBlockingDeque.