dosync

added
1.0

ns
clojure.core

type
macro

(dosync & exprs)

Runs the exprs (in an implicit do) in a transaction that encompasses
exprs and any nested calls.  Starts a transaction if none is already
running on this thread. Any uncaught exception will abort the
transaction and flow out of dosync. The exprs may be run more than
once, but any effects on Refs will be atomic.

                ;; Keep dosync body free of side-effects:
(defn my-thread-unsafe-fn [important-ref]
    (let [start-work (ref false)]
       (dosync
           (when (not @important-ref)
                ;"If a conflict occurs between 2 transactions 
                ;trying to modify the same reference, 
                ;one of them will be retried."
                ;http://clojure.org/concurrent_programming
                (ref-set important-ref true)
                (ref-set start-work true)))
        (when @start-work 
             ;launch side-effects here
            )))

            
                ;; Create 2 bank accounts
(def acc1 (ref 100))
(def acc2 (ref 200))

;; How much money is there?
(println @acc1 @acc2)
;; => 100 200

;; Either both accounts will be changed or none
(defn transfer-money [a1 a2 amount]
  (dosync
    (alter a1 - amount)
    (alter a2 + amount)
    amount)) ; return amount from dosync block and function (just for fun)

;; Now transfer $20
(transfer-money acc1 acc2 20)
;; => 20

;; Check account balances again
(println @acc1 @acc2)
;; => 80 220

;; => We can see that transfer was successful