How are you replacing the reference to the original map? If you're just using plain assignment e.g. x.myMap = newMap then that's not safe. You could use sync/atomic.Value if you always made sure to do map reads via the Load method.
On Mon, Sep 12, 2016 at 5:04 PM, sqweek E. <sqw...@gmail.com> wrote: > Ok so after getting away with using maps to share data between threads for a > loooong time, I've finally seen the light and accepted that this is not > safe. > > In my case the threads in question are a painter thread and a mouse/keyboard > event processing thread. They want to share data because obviously a mouse > hitbox needs to match what is being drawn on the screen, unless you're going > for a ux that drives your users insane :) > > Anyway as I said it's not safe to concurrently read and write a map; > eventually this will result in a panic. Yet I'm stuck with a codebase that > does this all over the place. So despite hating the thought of blocking > either thread I did what any honest java-for-dayjob coder would do and > resigned myself to hiding the maps behind an RWLock. > > Of course things are never that simple; adding locks to code that was not > designed with them in mind is a good way to introduce deadlocks > (particularly of the > recursive-read-lock-while-other-thread-is-acquiring-write-lock variety). I > made another change to address recursive lock acquisition, realised I missed > a couple of shared maps and suddenly locking code was strewn all over my > program; I got to the point of acquiring a read-lock every time the mouse > moved before giving up in disgust. I thought about using an actual > concurrent map, but giving up the builtin map's ease of use and > well-typedness didn't thrill me. After some thought I came up with an > alternative approach... > > TLDR; My shared structures are *mostly* read-only, in the sense that read > operations are much more common than writes. I decided I can afford to > change the writes so instead of updating the maps in place, they (a) take a > copy of the current map (b) update the copy and (c) replace the reference to > the original map (held in a struct field) with the updated copy. > > I was pretty chuffed with this approach. It's clearly not the most efficient > but it allowed me to solve the panic without risking deadlock. I'd be > surprised if I'm the first person to come up with it, but I haven't seen it > mentioned - the majority of advice seems to be "use an RWLock" or "use a > concurrent map". > > I'm interested in understanding how safe/portable the approach is. I'm no > expert on ARM/memory barriers but my understanding is that without an > explicit sync/channel operation there's no guarantee another thread will see > a change (in this case, the new map instance). In my case I have a channel > based notification mechanism running alongside to wake up the painter thread > when something changes, I'm just not sure what memory changes that is > guaranteed to communicate. > > I also just wanted to share the approach and see how other people feel about > it. It reminds me a bit of a double-buffering - writing to the backbuffer > and then swapping it into action. > > -sqweek > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.