Smith Cruise
Smith Cruise

Reputation: 444

A problem about golang concurrency in once

I am reading the official document, there is a code that I can't understand.

var a string
var done bool

func setup() {
    a = "hello, world"
    done = true
}

func doprint() {
    if !done {
        once.Do(setup)
    }
    print(a)
}

func twoprint() {
    go doprint()
    go doprint()
}

This version can (incorrectly) print an empty string instead of "hello, world".

Why this code may produce wrong results.

Upvotes: 0

Views: 555

Answers (2)

LOL_Overflow
LOL_Overflow

Reputation: 23

Just to further explain the accepted answer, in Go, compilers and processors may reorder reads/writes. In a single go routine, such reordering is guaranteed to not affect the behavior.

However, in your example, there are multiple go routines without synchronization and reordering DOES have an impact. Imagine the first go routine executes done=true then a=xxxx, if the second go routine executes after first done=true and before a=xxxx, it will produce an empty string.

Upvotes: 0

icza
icza

Reputation: 418555

Because in doprint() the done variable is is accessed (read) without synchronization.

Imagine the first goroutine running doprint() completes before the second is scheduled to run. The first writes done (in setup()), and the 2nd goroutine tries to read done: should that read produce the result written by the first goroutine? There is no synchronization: undefined behavior. It may be that done will be observed as true, and thus setup() will not be called, and it may be the write to a will not be observed and thus the initial zero value (empty string) is printed.

Reads of variables always observe previous writes (previous in time) in a single goroutine. Writes made by a goroutine are not guaranteed to be observed in another goroutine unless there is synchronization between them.

Upvotes: 3

Related Questions