Sync.once infinite lock when used from multiple goroutines

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.

Your program has a data race, run it with -race to see where.

Thanks Dave! I was unaware of that useful -race build option.

Also found this suggested workaround on how to reset the sync.Once properly: https://medium.com/@matryer/sync-once-with-reset-in-golang-quicktip-6ac44b015256#.urxacgxso

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.