Thread synchronization with Clojure

  • A+
Category:Languages

I got an exercise:

  • Print in order all positive integers from 1 to 100.

  • Using blocks, semaphores or other similar mechanisms (but avoiding sleep), coordinate two threads such that the combined output from both threads appears in numerical order.

     Sample Output     In thread one: The number is ‘1’     In thread two: The number is ‘2’     In thread one: The number is ‘3’     In thread two: The number is ‘4’ 

The exercise is for Ruby, but I'd like to show to my class that Clojure could be a good option for the task.

I don't have any experience with threads in any language, but I was thinking to use something like:

 (def thread_1 (future (swap! my-atom inc) ))  (def thread_2 (future (swap! my-atom inc) )) 

but @thread_1 always returns the same vale. Is there a way to coordinate two threads in Clojure?

I found this example in Java using ReentrantLock and Condition, and now I'm trying to translate it to Clojure.

 


If the order of threads does matter and if you are curious about non-classical thread communication, you could go with clojure.core.async and use "channels".

(require '[clojure.core.async :as a])  (let [chan-one (a/chan 1)       chan-two (a/chan 1)]   (a/>!! chan-one 1)   (doseq [[thread in out] [["one" chan-one chan-two]                            ["two" chan-two chan-one]]]     (a/go-loop []       (when-let [n (a/<! in)]         (if (> n 10)           (do (a/close! in)               (a/close! out))           (do (prn (format "In thread %s: The number is `%s`" thread n))               (a/>! out (inc n))               (recur))))))) 

The output is

"In thread one: The number is `1`" "In thread two: The number is `2`" "In thread one: The number is `3`" "In thread two: The number is `4`" "In thread one: The number is `5`" "In thread two: The number is `6`" "In thread one: The number is `7`" "In thread two: The number is `8`" "In thread one: The number is `9`" "In thread two: The number is `10`" 

One gotcha here is that go-routines are executed in a thread pool, so they are not dedicated threads, and if you want to use real threads you should go this way:

(require '[clojure.core.async :as a])  (let [chan-one (a/chan 1)       chan-two (a/chan 1)]   (a/>!! chan-one 1)   (doseq [[thread in out] [["one" chan-one chan-two]                            ["two" chan-two chan-one]]]     (a/thread       (loop []         (when-let [n (a/<!! in)]           (if (> n 10)             (do (a/close! in)                 (a/close! out))             (do (prn (format "In thread %s: The number is `%s`" thread n))                 (a/>!! out (inc n))                 (recur)))))))) 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: