Search code examples
multithreadinggomemory-model

Go Memory Model Happens Before (Channels with Shared State)


I'm trying to more fully understand the nature of the Happens-Before relationship between channels and other shared state. Specifically, I want to see if some kind of memory fence is created on a channel send and receive operation.

For example, if I send a message on a channel, do all other operations surrounding modification of shared state "happen before" the send/receive operation. In my particular example, I'm only ever writing from a single go routine and then reading from a single go routine.

(Aside: the obvious answer in the example below is to put an instance of the Person struct on the channel directly, but that's not what I'm asking.)

package main

func main() {
    channel := make(chan int, 128)

    go func() {
        person := &sharedState[0]
        person.Name = "Hello, World!"
        channel <- 0
    }()

    index := <-channel
    person := sharedState[index]
    if person.Name != "Hello, World!" {
        // unintended race condition
    }
}

type Person struct{ Name string }

var sharedState = make([]Person, 1024)

Solution

  • The memory model guarantees that when the channel write operation executes, all operations in that goroutine that comes before the channel operation are visible. So in your example, the "unintended race condition" cannot happen, because when the channel is read, the assignment happened in the goroutine is visible. This, of course, assumes that there isn't another goroutine that's writing to that same variable. If there was another goroutine writing to that same variable, then you would need to synchronize that goroutine as well to avoid the race.