Implements Clojure-styled concurrency operations such as `future` and `promise`.
clj-con defines a set of concurrency operations modeled after their Clojure
counterparts. Sample operators include
atom. See the exported symbols in package.lisp for the full list.
Or, if you're familiar with the Clojure Cheatsheet, the project implements the following:
If you didn't get this via quickload from the quickload repo (because it isn't
there yet), add it to your
~/quicklisp/localprojects/ directory, update/wipe
system-index.txt file accordingly, and then you can quickload it.
;; See 'local-projects' note in preceding paragraph (ql:quickload :clj-con) ; to use the code
;; To run the test (again, see 'local-projects' note) (ql:quickload :clj-con-test) (clj-con-test:run-tests)
The current implementation was tested on
abcl successfully (with
20 iterations of
run-tests on each, because, you know, threads and all).
The definitions are meant to be portable and are implemented entirely on Bordeaux Threads, but for those same reasons they aren't terribly efficient (as BT has no condition variable broadcast, no compare-and-set, and so on). At some point I could see adding some optimized conditional compilations.
Differences from Clojure
swap-vals! return vectors in Clojure but return
multiple values here. I couldn't see the point of returning vectors when CL
has no destructuring bind (outside of LOOP?) that works on vectors. At least you can use
multiple-value-bind if you want.
atom package conflict
If you're going to
(use :clj-con), note that
atom requires a
(:shadowing-import-from #:clj-con #:atom). I'm open to better ways to do
this, I'm not much practiced in the arts of Common Lisp packages.
The Java Virtual Machine's threading tools are really a marvelous thing. If
you've been in that ecosystem a long time, going back to pthreads with some of
its limitations (or lisp oddities built on them), will feel fragile, and
reading the various SBCL source comments on
interrupt-thread doesn't do much
to prevent that feeling.
As this implementation is more a trial balloon than anything else, have a care about repeatedly interrupting threads or using complicated mission critical handlers in the threads unless you have taken to heart the use of WITHOUT-INTERRUPTS and other implementation dependent things. I didn't hit any problems with my simple tests but that isn't saying much.
There is no attempt here to bring clojure syntax or persistent data structures to Common Lisp. Fortunately neither of those things is particularly prevalent in Clojure's concurrency operator model, at least not in the clojure.core namespace.
Some enterprising person might want to make a readtable that maps
deref, assuming it doesn't conflict with
,@, but that hasn't been done
here so you'll just have to call
If you're missing clojure.core.async and want some blocking queues for producer/consumer
situations, take a look at the
(ql:quickload :lparallel). Unlike clojure.core.async it has a
peek operator which I find useful
when I need to speculatively try something on a queue element without losing FIFO ordering.