Fork me on GitHub

In the Clojure/Java implementation of core.async, what kind of Java synchronization techniques, if any, are used when a go block switches from running in one thread T1, to running in a different thread T2? (feel free to correct any misimpressions that may be revealed in the question itself)

Alex Miller (Clojure team)21:09:45

go blocks become suspended computations (ie functions) that are invoked


Can a go block be parked after running in thread T1, then later woken and run in thread T2?


and any "local data" in the go block will not necessarily have gone through any synchronization mechanisms, unless the Clojure developer adds them?

Alex Miller (Clojure team)21:09:11

where would "local data" be?


loop/let symbols, fn. parameters, ...

Alex Miller (Clojure team)21:09:55

it'll be run in the context of restored local bindings etc


saved and restored local bindings, with or without Java synchronization mechanisms provided by the core.async implementation machinery?

Alex Miller (Clojure team)21:09:24

I think those are saved in an atom

Alex Miller (Clojure team)21:09:41

stretching the limit of my memory


I can look this up myself in the code, if it isn't on the tip of your brain -- not trying to get you to do any extensive time digging here.

Alex Miller (Clojure team)21:09:10

that's about as far as I remember, have to run anyhow


thanks for the info


its an atomic array


bindings created with binding are also saved and restored as the go block moves between threads (I think there are some outstanding issues with that though)


where locals would be saved in to the, uh, stackframe I guess on the jvm they instead get stored into the atomic array


and the array has a few extra slots for other bits of dynamic information, bindings, exception handlers


So if a go block has mutable data that it modifies, and doesn't explicitly try to synchronize it, the act of core.async writing references to such mutable data into an AtomicReferenceArray in thread T1, then reading it back out when restoring in thread T2, should synchronize all of those changes made by T1 and make them visible in T2. (statement, not question -- but corrections welcome)


I vaguely get the sense that is the idea, but I don't know enough to evaluate if that goal is successful achieved


I think I have seen tickets where people have argued you could use a regular array in the go implementation, relying on the channel locks for visibility


Sounds like a bit more "global" property of the implementation, and thus a bit harder to check, and easier to break, but it does seem at least possible in principle.