I'm keeping a registry of processes in an atom.
I want to start one and only one process (specifically a core.async go-loop) per id
.
However, you're not supposed to perform side-effects in a swap!
, so this code is no good:
(swap! processes-atom
(fn [processes]
(if (get processes id)
processes ;; already exists, do nothing
(assoc processes id (create-process! id)))))
How would I go about doing this correctly?
I have looked at locking
, which takes an object as a monitor for the lock. I would prefer that each id
- which are dynamic - have their own lock.
It seems that you need to protect processes-atom
from concurrent modification, so that only single thread can have access to it. locking
will work in this case. Since, by usage of locking
, we will manage thread safety by ourselves, we can use volatile
instead of atom
(volatile
is faster, but doesn't provide any thread-safety and atomicity guaranees).
Summing up the above, something like below should work fine:
(def processes-volatile (volatile! {}))
(defn create-and-save-process! [id]
(locking processes-volatile
(vswap! processes-volatile
(fn [processes]
(if (get processes id)
processes
(assoc processes id (create-process! id)))))))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With