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.

Reply via email to