How to correctly use sync.Cond?

前端 未结 8 805
忘了有多久
忘了有多久 2021-02-01 16:11

I\'m having trouble figuring out how to correctly use sync.Cond. From what I can tell, a race condition exists between locking the Locker and invoking the condition\'s Wait meth

相关标签:
8条回答
  • 2021-02-01 17:16

    Here's a practical example with two go routines. They start one after another but the second one waits on a condition which is broadcast by the first one before proceeding:

    package main
    
    import (
        "sync"
        "fmt"
        "time"
    )
    
    func main() {
        lock := sync.Mutex{}
        lock.Lock()
    
        cond := sync.NewCond(&lock)
    
        waitGroup := sync.WaitGroup{}
        waitGroup.Add(2)
    
        go func() {
            defer waitGroup.Done()
    
            fmt.Println("First go routine has started and waits for 1 second before broadcasting condition")
    
            time.Sleep(1 * time.Second)
    
            fmt.Println("First go routine broadcasts condition")
    
            cond.Broadcast()
        }()
    
        go func() {
            defer waitGroup.Done()
    
            fmt.Println("Second go routine has started and is waiting on condition")
    
            cond.Wait()
    
            fmt.Println("Second go routine unlocked by condition broadcast")
        }()
    
        fmt.Println("Main go routine starts waiting")
    
        waitGroup.Wait()
    
        fmt.Println("Main go routine ends")
    }
    

    Output may vary slightly as the second go routine could start before the first one and viceversa:

    Main go routine starts waiting
    Second go routine has started and is waiting on condition
    First go routine has started and waits for 1 second before broadcasting condition
    First go routine broadcasts condition
    Second go routine unlocked by condition broadcast
    Main go routine ends
    

    https://gist.github.com/fracasula/21565ea1cf0c15726ca38736031edc70

    0 讨论(0)
  • 2021-02-01 17:16

    You need to make sure that c.Broadcast is called after your call to c.Wait. The correct version of your program would be:

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func main() {
        m := &sync.Mutex{}
        c := sync.NewCond(m)
        m.Lock()
        go func() {
            m.Lock() // Wait for c.Wait()
            c.Broadcast()
            m.Unlock()
        }()
        c.Wait() // Unlocks m, waits, then locks m again
        m.Unlock()
    }
    

    https://play.golang.org/p/O1r8v8yW6h

    0 讨论(0)
提交回复
热议问题