Reputation: 127
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
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
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