I have a piece of code in clojure which should run on isolation. Lets say this function is
(defn isolate [string1])
Its easy to isolate the whole function on all inputs, calling it like so :
(def o (Object. ))
(locking o (isolate string1))
However this only allows one process/thread to access isolate simultaneously.
What I have now implemented is the following :
(def current-locks (ref {}))
(defn mergeReverse [x y] (merge y x))
(defn merge-with-current-locks [key val]
(dosync (alter current-locks mergeReverse {key val})))
(defn remove-lock [key]
(dosync (alter current-locks dissoc key)))
and finally the threads block calling this method
(defn block-until-free [key val]
(let [_ (merge-with-current-locks key val)]
(if (dosync (and (contains? current-locks key)
(not= (get current-locks key) val)))
(do
(Thread/sleep 10)
(block-until-free key val)))))
As you can see in the solution I used keys and values here and although I only lock on the keys but being able to use maps instead of arrays was beneficial since I used the merge property that merges in a map only if map does not contain this value and since the current-locks is a ref I used alter and swapped the merge inputs to acquire the needed behaviour.
This hack works as far as I can tell (and I tested it). But my question is how can I do this in a correct clojure way? This solution seems complicated
Off course the remove-lock has to be called once the critical function is executed.