On the write side, you write your mult-GB data using normal writes, then atomic.Store for the final flag uint. On the read side, you use an atomic.Load for the flag uint followed by regular loads for the remaining multi-GB of data. Reading a particular flag value ensures that the following loads see all the writes from before the writer wrote that particular flag value. This is guaranteed by the memory model, as the atomic read seeing the atomic write introduces the synchronized-before edge you need.
I agree that the Go memory model doesn't directly address multi-process communication like this, but assuming both ends are Go this is guaranteed to work by the Go memory model. YMMV on what operations/barriers/etc. you need in other languages. On Saturday, January 21, 2023 at 1:46:09 PM UTC-8 bse...@computer.org wrote: > On Sat, Jan 21, 2023 at 12:11 PM Peter Rabbitson (ribasushi) < > riba...@gmail.com> wrote: > >> On Saturday, January 21, 2023 at 7:48:12 PM UTC+1 bse...@computer.org >> wrote: >> On Sat, Jan 21, 2023 at 10:36 AM Peter Rabbitson <riba...@gmail.com> >> wrote: >> Greetings, >> >> I am trying to understand the exact mechanics of memory write ordering >> from within the same goroutine. I wrote a self-contained runnable example >> with the question inlined here: https://go.dev/play/p/ZXMg_Qq3ygF and am >> copying its header here: >> >> // Below is a complete example, with the question starting on line 38: >> // how do I ensure that a *separate Linux OS process* observing `IPCfile` >> // (either via pread() or mmap()) can *NEVER* observe W2 before W1. >> // The only permissible states are: >> // 1. no changes visible >> // 2. only W1 is visible >> // 3. both W1 and W2 are visible >> >> This is based on my interpretation of the go memory model: >> >> Atomic memory operations are sequentially consistent, so here: >> >> (*mmapBufAtomic.Load())[fSize-1] = 255 // W1 >> (*mmapBufAtomic.Load())[0] = 42 // W2 >> >> The first atomic load happens before the second load. That also implies >> the first write (W1) happens before the second (W2). However, there is no >> guarantee that W2 will be observed by another goroutine. >> >> This is perfectly acceptable ( see point 2. above ). Also note that there >> is no other goroutine that is looking at this: the observers are separate ( >> possibly not even go-based ) OS processes. I am strictly trying to get to a >> point where the writer process exemplified in the playground will issue the >> CPU write instructions in the order I expect. >> >> >> I think what is really needed here is an atomic store byte operation. If >> this is the only goroutine writing to this buffer, you can emulate that by >> atomic.LoadUint32, set the highest/lowest byte, then atomic.StoreUint32 >> >> This would not be viable: the W1 write is a single byte for the sake of >> brevity. In practice it will be a multi-GiB write, with a multi-KiB write >> following it, followed by a single-UInt write. All part of a lock-free >> "ratcheted" transactional implementation, allowing for incomplete writes, >> but no dirty reads - the "root pointer" is the last thing being updated, so >> an observer process sees "old state" or "new state" and nothing inbetween. >> This is why my quest to understand the precise behavior and guarantees of >> the resulting compiled program. >> > > > You realize, if W1 is a multi-GB write, another process will > observe partial writes for W1. But, I believe, if another process observes > W2, then it is guaranteed that all of W1 is written. > > I think the Go memory model does not really apply here, because you are > talking about other processes reading shared memory. What you are really > relying on is that on x86, there will be a memory barrier associated with > atomic loads. I don't know how this works on arm. I am not sure how > portable this solution would be. The memory model is explicit about > observing the effects of an atomic write operation, and sequential > consistency of atomic memory operations. So it sounds like an unprotected > W1 followed by an atomic store of W2 would still work the same 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 golang-nuts...@googlegroups.com. >> > To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/c23d512e-a307-4f4d-bf23-74398c5cf42bn%40googlegroups.com >> >> <https://groups.google.com/d/msgid/golang-nuts/c23d512e-a307-4f4d-bf23-74398c5cf42bn%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- 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/82182584-9218-44a8-8e93-f491ea0df248n%40googlegroups.com.