Search code examples
gomutexdefer-keyword

Can you get a data race when deferring a mutex unlock in go?


Is this Get method buggy and prone to a theoretical data race?

type item struct {
    val   int
    mutex sync.RWMutex
}

func (i *item) Set(val int) {
    i.mutex.Lock()
    defer i.mutex.Unlock()
    i.val = val
}

func (i *item) Get() int {
    i.mutex.RLock()
    defer i.mutex.RUnlock()
    return i.val
}

I ask because I saw a rare data race when running my tests with -race with the former code, but can't find any way of duplicating the effect.

Is it possible for i.val to be set to a different value between when the defer carries out the RUnlock, and when we read and return the value from the struct?

Must Get() be something like this instead?:

func (i *item) Get() int {
    i.mutex.RLock()
    defer i.mutex.RUnlock()
    val := i.val
    return val
}

Solution

  • Your code is safe, deferred functions are executed after the expression list of the return statement is evaluated. If you would have named result parameters, the return values would also be assigned to them before calling the deferred functions (and you could even modify the return values before "truly" returning from the enclosing function).

    No need to create a local variable to store i.val.