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)
channels have a mutex
go blocks become suspended computations (ie functions) that are invoked
when woken from a park
Can a go block be parked after running in thread T1, then later woken and run in thread T2?
yes
that's the whole idea
and any "local data" in the go block will not necessarily have gone through any synchronization mechanisms, unless the Clojure developer adds them?
where would "local data" be?
loop/let symbols, fn. parameters, ...
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?
I think those are saved in an atom
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.
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)
One of these, I suppose? https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReferenceArray.html
where locals would be saved in to the, uh, stackframe I guess on the jvm they instead get stored into the atomic array
yeah
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.