The trick is there are two sorts of atomic update, the first, the one you mention states that so long as the value is naturally aligned (if it’s a 32 but value, say, then it is always written to an address which is a multiple of four) then another processor will not observe the value half written. The explain what that means, consider an unaligned write, where a 32 bit value is written to an address who’s bottom two bits are not zero. In this case the processor has to perform writes, spanning the boundary. Another processor can then observe this partially updated value. It’s colloqually known as a torn write. There is also a performance penalty for doing this, which is why many processors do not let you read and write unaligned data. This is their way of ensuring this first kind of atomic property.
However, as we’re talking about multiple processes we need to talk about visibility, caches, and write back. This is the second kind of atomic write. This states that for a value written to memory by one processor to be visible to another you need to use a memory fence. The name fence comes from the notion of stopping. The memory fence operation tells each processor that when the get to the fence they have to stop until thr memory writes they issues have been flushed to memory. The same is true for reads, you use a fence operation to tell the processor to stop and synchronise with any outstanding writes to memory. In this way a program can know that a value has been written to memory and visible to other processes. This is called publishing, we say a value is safely published if it uses the correct memory fence operations.
In terms of Go, memory fence operations are taken care of by the sync/atomic package, so you have to use that if you want to use a value in memory as a communication channel between two goroutines.