Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Idiomatic Clojure way to spawn and manage background threads

What is the idiomatic Clojure way to create a thread that loops in the background doing updates to some shared refs and to manage its lifetime? I find myself using future for this, but it feels like a little bit of a hack as I never return a meaningful value. E.g.:

(future (loop [] (do
    (Thread/sleep 100)
    (dosync (...))
    (recur))))

Also, I need to be careful to future-cancel this when the background processing is no longer needed. Any tips on how to orchestrate that in a Clojure/Swing application would be nice. E.g. a dummy JComponent that is added to my UI that is responsible for killing the thread when the window is closed may be an idea.

like image 517
pauldoo Avatar asked Mar 13 '11 18:03

pauldoo


1 Answers

You don't need a do in your loop; it's implied. Also, while there's nothing wrong with an unconditional loop-recur, you may as well use (while true ...).

future is a fine tool for this; don't let it bother you that you never get a value back. That should really bother you if you use an agent rather than a future, though - agents without values are madness.

However, who said you need to future-cancel? Just make one of the steps in your future be to check whether it's still needed. Then no other parts of your code need to keep track of futures and decide when to cancel them. So something like

(future (loop []
          (Thread/sleep 100)
          (when (dosync
                 (alter some-value some-function))
            (recur)) ; quit if alter returns nil
          ))

would be a viable approach.

like image 179
amalloy Avatar answered Nov 01 '22 20:11

amalloy