It is not the writing - it is the reading, and what is “visible”. The point was that you need to use atomics if you write to ANY structure field and read that field from another Go routine - barring any other synchronization method (WaitGroup, Lock, etc.)
The secondary point is, if you use atomics, then there can be a performance hit due to false sharing, which is why I stated you can use gaps between this elements (in the example, use a larger array and put the counters at one every N elements) to avoid this. False sharing is typically understood to be referencing the performance issue - not a correctness issue. > On Feb 1, 2019, at 12:20 PM, roger peppe <[email protected]> wrote: > > > > On Fri, 1 Feb 2019, 4:11 pm robert engels <[email protected] > <mailto:[email protected]> wrote: > There is nothing reading the value in that code - so that would always be > safe… > > Here is a more common example that many people get wrong (pseudo code) > > struct { > a int > } > > go routine #1: > > for { > A.a = A.a + 1 > } > > go routine #2 : > > for { > if A.a > 100 { > break > } > > > Go routine #2 may never see the value of A.a change and so never exit the > loop. > > Indeed, though the topic here was specifically about writing to different > fields of the same struct. > > > > >> On Feb 1, 2019, at 9:43 AM, roger peppe <[email protected] >> <mailto:[email protected]>> wrote: >> >> On Fri, 1 Feb 2019, 3:18 pm Robert Engels <[email protected] >> <mailto:[email protected]> wrote: >> To clarify though, you still need to use atomics. >> >> Really? For writing to different fields in a struct? So the following code >> is not generally safe? >> (I often rely on this kind of code being safe so if it isn't, I need to >> know!). >> >> type S struct { >> a A >> b B >> } >> >> func (s *S) W() { >> var wg sync.WaitGroup >> wg.Add(2) >> go func() { >> var a A >> s.a = a >> wg.Done() >> }() >> go func() { >> var b B >> s.b = b >> wg.Done() >> }() >> wg.Wait() >> } >> >> >> On Feb 1, 2019, at 8:52 AM, roger peppe <[email protected] >> <mailto:[email protected]>> wrote: >> >>> >>> >>> On Thu, 3 Aug 2017, 8:45 am Dave Cheney <[email protected] >>> <mailto:[email protected]> wrote: >>> >>> >>> On Thu, 3 Aug 2017, 17:39 Dave Cheney <[email protected] >>> <mailto:[email protected]>> wrote: >>> Your first program has a data race, well it has two races, the first is a >>> data race between the goroutines writing to the slice and the println which >>> will read the contents of the slice. That is, if those writing goroutines >>> get a chance to run before main exits. >>> >>> The second program doesn't have a data race as the waitgroup.done / wait >>> creates a happens before relationship between reader and writer. >>> >>> >>> On Thu, 3 Aug 2017, 17:33 Henrik Johansson <[email protected] >>> <mailto:[email protected]>> wrote: >>> But isn't this what is happening in the example? Or is write-only not >>> sharing? >>> >>> >>> On Thu, 3 Aug 2017, 09:23 Dave Cheney, <[email protected] >>> <mailto:[email protected]>> wrote: >>> IMO you need a lock whenever you are sharing a value between goroutines by >>> storing it in memory. >>> >>> >>> On Thu, 3 Aug 2017, 17:21 Henrik Johansson <[email protected] >>> <mailto:[email protected]>> wrote: >>> I think I am mostly after a mental pattern to easily recognise when >>> synchronizations are needed. >>> >>> I am decently good at this but I tend to be very conservative and use locks >>> and atomics perhaps when they are not needed. >>> But here we have several goroutines all taking part in the initialisation >>> itself concurrently writing to the same array. How can this be safe in >>> light of https://golang.org/ref/mem#tmp_10 >>> <https://golang.org/ref/mem#tmp_10> . I get that your comment about >>> "happens before" comes in here if there were any readers but eventually >>> there will be readers or we would never need to do this. If the main after >>> some time wants to access these values is it enough to make sure the >>> goroutines are done perhaps using a WaitGroup or do we have to use some >>> other synchronisation to ensure the visibility of the data in the array? >>> >>> https://play.golang.org/p/8BfrPhyIEb <https://play.golang.org/p/8BfrPhyIEb> >>> >>> Or is it needed to do something like this: >>> >>> https://play.golang.org/p/9QgTP5Dqc7 <https://play.golang.org/p/9QgTP5Dqc7> >>> >>> I mean aside from the poor form of sleeping like this, the idea is to >>> simulate usage "at some point later in time". >>> >>> It gets hypothetical pretty quick and usually when this happens I make sure >>> to create a new array/slice/whatever and then atomically swap it before >>> some other goroutine uses it but I generally avoid indexing assignment from >>> go routines like this even though it seems to be ok. >>> >>> Does this hold for slices as well as for arrays? >>> >>> Yes, it is safe for multiple goroutines to write to different array >>> elements, the same is true for slices as they are backed by an array >>> >>> What about assignments to fields in structs? >>> >>> Yes. >>> >>> Can several goroutines safely write to different fields in the same struct >>> assuming they are word sized? >>> >>> Yes, although they should also be naturally aligned. >>> >>> Can you explain your reasoning here a little more, please? As far as I am >>> aware it is always ok to write concurrently to different fields in the same >>> struct and if that's not the case then I have some serious code review to >>> do! >>> >>> >>> Does this hold for all architectures? >>> >>> Some architectures have issues with atomic writes to values smaller than a >>> word. Look for xor8 in the runtime source. >>> >>> Writing to adjacent memory locations will cause false sharing between CPU >>> caches. This is a performance, not a correctness issue. >>> >>> >>> I am sorry if I am still a bit unclear but I find it hard to ask properly >>> when I am a bit unsure of the topic. :D >>> >>> >>> >>> tors 3 aug. 2017 kl 07:49 skrev Dave Cheney <[email protected] >>> <mailto:[email protected]>>: >>> I'm not really sure what you are asking. I think your second paragraph got >>> eaten by autocorrect at the critical point. Could try maybe asking your >>> question in a different way? >>> >>> >>> -- >>> 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 [email protected] >>> <mailto:golang-nuts%[email protected]>. >>> For more options, visit https://groups.google.com/d/optout >>> <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 [email protected] >>> <mailto:[email protected]>. >>> For more options, visit https://groups.google.com/d/optout >>> <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 [email protected] >>> <mailto:[email protected]>. >>> For more options, visit https://groups.google.com/d/optout >>> <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 [email protected] >> <mailto:[email protected]>. >> For more options, visit https://groups.google.com/d/optout >> <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 [email protected] > <mailto:[email protected]>. > For more options, visit https://groups.google.com/d/optout > <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 [email protected]. For more options, visit https://groups.google.com/d/optout.
