ryoakg
5/2/2016 - 10:14 AM

commute.clj

(require '[clojure.pprint :refer :all])

(def ^:dynamic *wait1* 0)
(def ^:dynamic *wait2* 0)
(def ^:dynamic *wait3* 0)
(def ^:dynamic *thread* nil)

(let [c (ref 0)
      transaction (fn []
                    (dosync
                     (Thread/sleep *wait1*)
                     (commute c (fn [c]
                                  (printf "%d|%s|1|%d\n" *thread*
                                          (System/currentTimeMillis)
                                          c)
                                  (inc c)))
                     (Thread/sleep *wait2*)
                     (commute c (fn [c]
                                  (printf "%d|%s|2|%d\n" *thread*
                                          (System/currentTimeMillis)
                                          c)
                                  (inc c)))
                     (Thread/sleep *wait3*)
                     (commute c (fn [c]
                                  (printf "%d|%s|3|%d\n" *thread*
                                          (System/currentTimeMillis)
                                          c)
                                  (inc c)))))
      f1 (future
           (binding [*thread* 1
                     *wait1* 0
                     *wait2* 200
                     *wait3* 0]
             (transaction)))
      f2 (future
           (binding [*thread* 2
                     *wait1* 100
                     *wait2* 0
                     *wait3* 200]
             (transaction)))]
  @f1 @f2
  nil)
;; 1|1462185909820|1|0
;; 2|1462185909920|1|0
;; 2|1462185909920|2|1
;; 1|1462185910020|2|1
;; 1|1462185910021|3|2
;; 1|1462185910021|1|0
;; 1|1462185910021|2|1
;; 1|1462185910021|3|2
;; 2|1462185910121|3|2
;; 2|1462185910121|1|3
;; 2|1462185910121|2|4
;; 2|1462185910121|3|5


;;; `alter` version
(let [c (ref 0)
      transaction (fn []
                    (dosync
                     (Thread/sleep *wait1*)
                     (alter c (fn [c]
                                  (printf "%d|%s|1|%d\n" *thread*
                                          (System/currentTimeMillis)
                                          c)
                                  (inc c)))
                     (Thread/sleep *wait2*)
                     (alter c (fn [c]
                                  (printf "%d|%s|2|%d\n" *thread*
                                          (System/currentTimeMillis)
                                          c)
                                  (inc c)))
                     (Thread/sleep *wait3*)
                     (alter c (fn [c]
                                  (printf "%d|%s|3|%d\n" *thread*
                                          (System/currentTimeMillis)
                                          c)
                                  (inc c)))))
      f1 (future
           (binding [*thread* 1
                     *wait1* 0
                     *wait2* 200
                     *wait3* 0]
             (transaction)))
      f2 (future
           (binding [*thread* 2
                     *wait1* 100
                     *wait2* 0
                     *wait3* 200]
             (transaction)))]
  @f1 @f2
  nil)
;; 1|1462185934477|1|0
;; 2|1462185934577|1|0
;; 1|1462185934678|2|1
;; 1|1462185934679|3|2
;; 2|1462185934878|1|3
;; 2|1462185934878|2|4
;; 2|1462185935078|3|5
(require '[clojure.pprint :refer :all])

(def ^:dynamic *wait* 0)

(let [ts (ref [])
      transaction (fn [] 
                    (dosync
                     (let [tm (System/currentTimeMillis)]
                       (commute ts (fn [ts]
                                     (Thread/sleep *wait*)                       
                                     (conj ts tm))))))
      f1 (future
           (binding [*wait* 7]
             (dotimes [_ 10]
               (transaction))))
      f2 (future
           (binding [*wait* 1]
             (dotimes [_ 100]
               (transaction))))]
  @f1 @f2
  (pprint @ts)
  (= @ts (sort @ts))) ;; => false (maybe)

(let [ts (ref [])
      transaction (fn [] 
                    (dosync
                     (let [tm (System/currentTimeMillis)]
                       (Thread/sleep *wait*)                       
                       (commute ts (fn [ts]
                                     (conj ts tm))))))
      f1 (future
           (binding [*wait* 7]
             (dotimes [_ 10]
               (transaction))))
      f2 (future
           (binding [*wait* 1]
             (dotimes [_ 100]
               (transaction))))]
  @f1 @f2
  (pprint @ts)
  (= @ts (sort @ts))) ;; => false (maybe)

;; `alter` version
(let [ts (ref [])
      transaction (fn [] 
                    (dosync
                     (let [tm (System/currentTimeMillis)]
                       (alter ts (fn [ts]
                                   (Thread/sleep *wait*)                       
                                   (conj ts tm))))))
      f1 (future
           (binding [*wait* 7]
             (dotimes [_ 10]
               (transaction))))
      f2 (future
           (binding [*wait* 1]
             (dotimes [_ 100]
               (transaction))))]
  @f1 @f2
  (pprint @ts)
  (= @ts (sort @ts))) ;; => true