Channel Synchronization in Clojure
Our example demonstrates how to use channels for synchronization between different threads in Clojure. This is similar to using channels to synchronize execution across goroutines in other languages.
(ns channel-synchronization
(:require [clojure.core.async :as async]))
;; This is the function we'll run in a separate thread. The
;; 'done' channel will be used to notify another thread
;; that this function's work is done.
(defn worker [done]
(print "working...")
(Thread/sleep 1000)
(println "done")
;; Send a value to notify that we're done.
(async/>!! done true))
(defn -main []
;; Start a worker thread, giving it the channel to
;; notify on.
(let [done (async/chan 1)]
(async/thread (worker done))
;; Block until we receive a notification from the
;; worker on the channel.
(async/<!! done)))
;; Run the main function
(-main)
To run this program:
$ clj -M channel-synchronization.clj
working...done
In this Clojure version, we’re using the core.async
library which provides Go-like channels and CSP-style concurrency. The async/thread
function is used to start a new thread, similar to launching a goroutine.
The worker
function simulates some work by sleeping for a second, then sends a value on the done
channel to signal completion.
In the -main
function, we create a channel, start the worker in a new thread, and then wait for the worker to finish by trying to receive from the done
channel.
If you removed the (async/<!! done)
line from this program, the program would exit before the worker
even started, similar to the behavior in the original example.
Note that in Clojure, we typically use >!!
and <!!
for blocking put and take operations on channels, respectively. The double-bang (!!) indicates that these are blocking operations.