--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-sympathy+unsub...@googlegroups.com.
On Mon, Jun 2, 2014 at 8:03 PM, Dan Eloff <dan....@gmail.com> wrote:
Yes the copy cannot be avoided, this is the copy-on-write pattern for a reason. You cannot make concurrent changes to a non-thread safe data structure (that's true for concurrent with just readers.) So the only way to do it safely is make a copy and modify the copy.
The alternative is to use an immutable/persistent data-structure, as in data structures that use structural sharing on changes. With Scala’s Map for example, you could simply do this and it would work:
myMap = myMap.updated("some-key", value)
// on another thread
myMap("some-key")
On updates, other threads will see either the old version or the new version, no intermediate state, no locks necessary and the seen snapshots can’t be destroyed by the producer.
The problem with persistent data-structures is that they are usually based on trees and/or linked-lists, but mostly trees, which means increased cache misses, although this is an active area of research - for example Scala’s Vector, which is a 32-wide tree and Scala’s Map, a persistent HAMT variant are pretty decent given the design constraints. They also blend well with atomic references (CAS updates) and with STM, however in high-contention scenarios this will stress the GC and it doesn’t scale as the contention can only happen at the root (Martin Thomson has an interview about it). However they perform fine if the updates are not contended (i.e. they are IMHO perfect for the above use-case), because shared reads need no synchronization and the producer doesn’t need to publish a full copy on updates. And if extreme throughput is not one’s focus, then the biggest advantage of persistent data-structures is that they are worry free.
Cases 1 and 2 are fine. In case 1 you probably don't even need the volatile modifier as it's very likely that the way you start the other threads or hand off the map to them already induces a happens-before edge.
Sent from my phone
--
This is actually known (at least I've seen it several times) to potentially cause a reader to enter an infinite loop if the bucket list it's traversing is modified at the "right" time by a writer.
Sent from my phone
> An issue thus far not discussed is map resizing. If a put(K,V) results in a resize the map internal array/arrays will be replaced which can lead to a broken view on the readers side(returning wrong value for key for instance). To fix this issue you will need to change the map implementation.
That's besides the point, even without the resizing it's unsafe to modify the map while readers may be reading it.
Should mention that I've seen this with HashMap, in case that wasn't clear.
Sent from my phone
Cases 1 and 2 are fine. In case 1 you probably don't even need the volatile modifier as it's very likely that the way you start the other threads or hand off the map to them already induces a happens-before edge
You don't need volatile in these cases, yes. In JMM terms, Thread.start() is a synchronizing action which means it creates a happens-before edge. Talking about caches, memory and registers isn't even needed here.
Sent from my phone
You don't need volatile in these cases, yes. In JMM terms, Thread.start() is a synchronizing action which means it creates a happens-before edge. Talking about caches, memory and registers isn't even needed here
An action that starts a thread synchronizes-with the first action in the thread it starts
On Tue, Jun 3, 2014 at 10:24 AM, ‘Nitsan Wakart’ via mechanical-sympathy [mechanica...@googlegroups.com](mailto:mechanica...@googlegroups.com) wrote:
An issue thus far not discussed is map resizing. If a put(K,V) results in a resize the map internal array/arrays will be replaced which can lead to a broken view on the readers side(returning wrong value for key for instance). To fix this issue you will need to change the map implementation.
Btw, Scala has an interesting mutable/concurrent map implementation called TrieMap, from which readers can read non-blocking snapshots, based on this paper: http://lampwww.epfl.ch/~prokopec/ctries-snapshot.pdf
Haven’t evaluated or used it yet, but it’s interesting nonetheless.