When using multiple goroutines to manipulate a shared sync.once object, the goroutines block indefinitely if the sync.once variable is reassigned to a new object.
In the sample code shown below, the “Ending goroutine…” statement is only printed for the first goroutine and not the others, can someone explain why this occurs?
Sample code is also at: https://play.golang.org/p/0r7PkQKg_u (copied below)
package main
import (
"fmt"
"sync"
"time"
)
func printHello() {
fmt.Println("Hello")
time.Sleep(2 * time.Second) // Block a little so all goroutines get a lock on the once mutex
}
func main() {
var once sync.Once
// Create 3 go coroutines and execute them
for i := 0; i < 3; i++ {
val := i
go func() {
fmt.Printf("Starting goroutine #%d\n", val)
once.Do(printHello)
once = sync.Once{} // Reset the sync; seems to cause problems
fmt.Printf("Ending goroutine #%d\n", val)
}()
}
time.Sleep(5 * time.Second)
fmt.Println("Exiting the application")
}
From debugging, I was observing that the last two goroutines remain blocked on the sync.once mutex’s lock, even after the mutex gets unlocked by the first goroutine (after it completed the once.Do() call). For some reason, it seems that reassigning the sync variable causes this issue. The intended goal of the reassignment of the sync, is to essentially reset the sync so that other goroutines created later, would do the ontime call.
Note: It seems to work well if I change the sync variable to a pointer and create it with new: https://play.golang.org/p/eraTtjiGJs
Thanks.