Database Reference
In-Depth Information
(swap! retries inc)
(Thread/sleep sleep-for)
(ref-set counter (inc c))
(send *agent* starve-out sleep-for)
tag))))
5.
If we send starve-out to both agents with very different sleep periods and look
at the output, we'll see that :a2 is consistently getting starvedout. (You can stop the
agents by calling shutdown-agents ):
user=> (start-agents starve-out 50 1000)
:starve-out :a2, :try 1, :counter 19
:starve-out :a2, :try 2, :counter 39
:starve-out :a2, :try 3, :counter 59
:starve-out :a2, :try 4, :counter 78
6.
In order to make this safe, we have to move all of the side effects out of the dosync
block. This means that we'll move the debug call out of the STM. While we're at it,
we'll move the send call since it's theoretically a side effect, even though it should
be safe enough here. To be safer, we'll use a new output function, one that uses io!
(highlighted). The io! block will throw an exception if it is executed inside
a transaction:
(defn debug! [msg] ( io! (debug msg)))
(defn starve-safe [tag sleep-for]
(let [retries (atom 0)]
(dosync
(let [c @counter]
(swap! retries inc)
(Thread/sleep sleep-for)
(ref-set counter (inc c))))
(when-not (zero? @retries)
(debug! (str ":safe-starve " tag
", :try " @retries
", " @counter)))
(send *agent* starve-safe sleep-for)
tag))
This version safely handles the I/O in the STM. Moreover, if we forget and refactor the call to
debug! back inside the transaction, our code will stop working.
 
Search WWH ::




Custom Search