Hi!

I would like to receive clarifications, if possible, on Go memory model
guarantees about non-atomic load and stores when intermixed with atomic load
and stores.

I'm reviewing a piece of code which, simplified, works as follows:

 - There is a single "writer" goroutine which

    - Allocates a new array, then uses sync/atomic.StorePointer to save the
      address of this array someplace.

    - Writes the array elements one by one.
      After writing each element it - again atomically - updates some memory
      location which contains the number of elements currently written in the
      array.

    - When the array fills up, it repeats the routine.

   A point to note is that the writer writes each element only once,
   and after it's done with the array, it never touches this array again.

 - There are multiple "reader" goroutines each of which consumes the data
   being updated by the "writer" in the following way:

    - Use sync/atomic.LoadPointer to obtain the address of the array currently
      in use by the "writer" goroutine.

    - Atomically read the current number of elements written in the array
      by the "writer" goroutine and then read that many elements
      from the array.

My problem is that I fail to properly apply the text of the Go memory model
to this case to figure out if there is still a data race on the elements
of these arrays between the writer and the readers.

The chief problem I have with my reasoning is that I fail to understand
whether the sequenced-before guarantees provided by atomics apply only to the
atomic operations theirselves - and the memory locations they operate on - or
to the whole sequences of statements executed by goroutines which perform
the atomic operations.

To simplify, and given the description of the algorithm above, I apply the
following reasoning.
A goroutine A performs multiple non-synchronized stores to memory locations X,
Y and Z, and then performs atomic store into memory location M. Naturally, all
store operations done on A up to and including the atomic store to M, are
naturally sequenced - all the non-synchronized stores has happened before the
atomic store.
Now a goroutine B uses atomic load of memory location M and then
performs multiple non-synchronized memory loads from memory locations X, Y
and Z. These non-synchronized loads are naturally sequenced after the atomic
load from M.
("Naturally sequenced" means it's just a regular program flow within a
goroutine.)
Given the above, is it guaranteed that A's stores to X, Y and Z are
synchronized-before B's loads from X, Y and Z?

My gut feeling is that no, Go does not provide this guarantee because of two
reasons:

 - The store performed by A to M does not depend on stores to X, Y and Z,
   and the compiler and/or the hardware are free to reorder them.

 - An atomic store operation is not required to perform a full memory fence,
   so even if no reordering has happened on any layer, the goroutine B
   can still obtain stale data from the CPU cache.

Hence I came to the conclusion that theoretically the code described above is
still prone to data races on the elements of the arrays.

On the other hand, a sample program implementing the algorithm described above
compiled with -race does not fail (8-core i7-8550U, linux/amd64, Go 1.17.13;
also tried other versions). I know that the race detector does only have no
false positives, but the possibility to detect a particular data race heavily
depends on the hardware and relative timings of the operations in a running
program, so the fact it does not see the data race here does not prove it is
not possible.

So, can anyone please help me analyze this case?

(Well, I also should admit the real code is more complicated than that but the
basic idea still holds: the implementor has tries to use atomics in the way
presented in the algorithm described.)

-- 
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.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/20221030132816.zrmrqxucsc2rf7ou%40carbon.

Reply via email to