| I rarely-but-sometimes want functions that are mutually atomic - only one of them can be running in one thread at any given time. Don't read that too carefully, you know what I mean :) Typically I'd use a mutex and each of the functions would lock on it before doing stuff. But arc doesn't have mutexes, it has 'atomic and 'atomic-invoke, and that's sort of inconvenient. Consider queues: (def enq (obj q)
(atomic ...))
(def deq (q)
(atomic ...))
If I'm reading this right, only one thread can be enqueueing (anything) at a time, and only one thread can be dequeueing (anything) at a time, yet two threads can be enqueueing and dequeueing the same queue at the same time, and step all over each other? That can't be right. (note that pg mostly uses enq-limit to mess with queues, which sidesteps this by wrapping everything in 'atomic. In the one case where he doesn't, on req-times* in the server, only one thread ever touches the queue).So, playing off the 'defs macro, I wrote 'atdefs, that translates this: (let glob* 0
(atdefs foo (bar) (++ glob* bar)
baz (x) (-- glob* x)))
into this (well, with gensyms instead of helpful names): (let glob* 0
(withs (f1 (fn (bar) (++ glob* bar))
f2 (fn (x) (-- glob* x))
gh (fn (call . args)
(atomic
(case call
foo (apply f1 args)
bar (apply f2 args)))))
(def foo args
(apply gh 'foo args))
(def bar args
(apply gh 'bar args))))
I think that's the right way to do it. I would've put g1/g2 right into the definition of gh, but would they be compiled procedures then? I'm not really sure.Here's the macro, feel free to improve it. I admit that I preserved the order of the args to 'case out of pure superstition. (mac atdefs args
(let (gh ga)
(apply (rfn helper (acc al . rest)
(if rest
(let (name args body . fns) rest
(w/uniq g
(apply helper
`((,g (fn ,args ,body)) ,@acc)
`((,g ,name) ,@al)
fns)))
(w/uniq (gh gc ga)
`(,gh ,(apply + (rev:cons
`(,gh (fn (,gc . ,ga)
(atomic
(case ,gc
,@(apply + (map (fn ((a b))
`(,b (apply ,a ,ga)))
(rev al)))))))
acc))))))
nil nil args)
(w/uniq gl
`(withs ,ga
,@(map (fn ((name args body))
`(def ,name ,gl
(apply ,gh ',name ,gl)))
(tuples args 3))))))
|