One way to think about the difference between alter and commute: With a commutative function, they both get to the same end result, but commute allows more concurrency, while guaranteeing less about the return value. In particular, with commute you might not be able to see every step by looking at the return values. If you want to see each step, as with runonce, you need alter.
That said, Chouser's AtomicBoolean is probably better unless the run statuses every need to be composed until a larger transaction. Just to make things even more fun: *None* of the proposed fixes to the concurrency bug in the original actually preserve the` semantics of the original. All have moved from "run (usually) once, mark as done" to "mark as done, try once". This also means that other threads could see a runonce as being done when it hasn't begun yet. Or, long story short, runonce doesn't really work unless you actually run the function inside the transaction. Fortunately, for my problem domain I don't need this to be perfect. Stuart On Nov 8, 2008, at 10:42 PM, Stephen C. Gilardi wrote: > > > On Nov 8, 2008, at 10:23 PM, Stuart Halloway wrote: > >> >> How about: >> >> (defn runonce >> "Create a function that will only run its argument once." >> [function] >> (let [call-count (ref 0)] >> (fn [& args] >> (when (= 1 (dosync (alter call-count inc))) >> (apply function args))))) > > The counter occurred to me too. I don't think it's necessary though. > What's important is that one thread "know" that it was the one that > cause the "false" to "true" transition. > > Regarding the value returned by dosync above, I'd believe it if > someone told me that it could only return 1 to one thread, one time, > guaranteed, but I've been wrong before in my reasoning about alter vs. > commute regarding what's possible, so I'll have to give it more > thought on correctness. > > Here's perhaps a more basic "one shot" building block: > > (defn once > "Returns a function that returns v the first time it's called and > nil every time after that" > [v] > (let [returned (ref false)] > (fn [] > (dosync > (when-not (ensure returned) > (ref-set returned true) > v))))) > > --Steve > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---
