Pavel
Pavel

Reputation: 127

Race condition. Cannot figure out why

A Race Condition occures when i'am running my code. It is a simple implementation of a concurrent safe storage. The Race Condition disappears when i change the reciever in get() method to (p *storageType). I'm confused. I need someone who could explain to me such a behaivior.

package main

type storageType struct {
    fc    chan func()
    value int
}

func newStorage() *storageType {
    p := storageType{
        fc: make(chan func()),
    }
    go p.run()
    return &p
}

func (p storageType) run() {
    for {
        (<-p.fc)()
    }
}

func (p *storageType) set(s int) {
    p.fc <- func() {
        p.value = s
    }
}

func (p storageType) get() int {
    res := make(chan int)
    p.fc <- func() {
        res <- p.value
    }
    return <-res
}

func main() {

    storage := newStorage()

    for i := 0; i < 1000; i++ {
        go storage.set(i)
        go storage.get()
    }
}

Upvotes: 1

Views: 122

Answers (2)

icza
icza

Reputation: 417797

In main() the storage variable is of type *storageType. If storageType.Get() has value receiver, then storage.get() means (*storage).get().

The get() call has storageType as the reciver, so the storage pointer variable has to be dereferenced to make a copy (that will be used as the receiver value). This copying means the value of the pointed storageType struct must be read. But this read is not synchronized with the run() method which reads and writes the struct (its value field).

If you change the receiver of get() to be a pointer (of type *storageType), then the receiver again will be a copy, but this time it will be a copy of the pointer, not the pointed struct. So no unsynchronized read of the struct happens.

See possible duplicate: Why does the method of a struct that does not read/write its contents still cause a race case?

Upvotes: 5

Micah Parks
Micah Parks

Reputation: 1942

First one: your main function doesn't wait for all goroutines to finish. All goroutines are forced to return when main does.

Look into using a sync.WaitGroup

Upvotes: -1

Related Questions