Fork me on GitHub
#clojure-dev
<
2019-09-10
>
andy.fingerhut02:09:49

I should probably send this to somewhere like the concurrency-interest email list if folks here do not know, but thought I would ask here first (in a sub-thread, for those uninterested).

andy.fingerhut02:09:05

So my understanding is that Java's ArrayBlockingQueue, for example, has a guarantee that there is a happens-before relationship for any object that one thread put's to it, and any thread that does a corresponding take on the same object.

andy.fingerhut03:09:19

That belief comes from this text in the docs for interface BlockingQueue: "Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a BlockingQueue happen-before actions subsequent to the access or removal of that element from the BlockingQueue in another thread."

andy.fingerhut03:09:44

All good stuff.

andy.fingerhut03:09:15

One earlier discussion I recall, but cannot find, was about cases where one could achieve what this page calls "thread isolation": https://clojure.org/reference/transients without using such techniques.

andy.fingerhut03:09:06

One example that I think was given was: in a single JVM, thread T1 writes a reference to some object C to a field F (F is not volatile, not final, and the access is protected by no locks -- no JMM synchronization is used), then "does something" to indicate it is done with C.

andy.fingerhut03:09:38

Thread T2 "does something" to know that it can start using C, then starts using it. C in this case could be a transient collection, or any other mutable Java object.

andy.fingerhut03:09:23

The "does something" that I was vague about above could be several things, I think none of them with any JMM synchronization guarantees, but sound plausible from a common sense point of view that one is guaranteed to happen before the other.

andy.fingerhut03:09:04

"does something #1": T1 sends a message over a socket to some other process, which is known by the developer to generate another particular message in response. T2 reads that response message.

andy.fingerhut03:09:50

"does something #2": Some file F is known not to exist initially. T1 creates the file F, and T2 spin loops checking for F to exist, exiting the loop when F exists.

andy.fingerhut03:09:49

"does something #3": T1 guarantees that it will do its write of F before 4:30pm Tuesday. T2 guarantees that it will do its read of F after 5:30pm the same Tuesday (and same time zone). This raises the question of how close T2's time could be to T1's time and still guarantee that it is "after", e.g. 4:30:00 plus 0.00001 seconds?

andy.fingerhut03:09:42

I mean, I know that the safe tried-and-true things here are stuff like shared data protected by locks, and queues with synchronization guarantees. All great and recommended. But if we don't simply say that "thread isolation" means use one of the techniques on a very short list, what else could we possibly say is known to work?

hiredman03:09:48

I know that is just a for instance, but calls to time apis, like System/nanoTime , are not guaranteed to increase monotonically between threads, e.g. T2 can get a time before the time T1 gets even if you ahave n atomic compare and set establishing an order where T1's read happens before T2's (I've had this lead to bugs generating time based IDs). So you would have to get relatively coarse timing wise.

hiredman03:09:57

You could borrow all kinds of techniques from distributed systems for defining an order of events without using shared memory. Event clocks maybe.