go - 使用 sync.Cond 时所有 go routines 都处于休眠状态

标签 go concurrency

func main() {
    type Button struct {
        Clicked *sync.Cond
    }
    button := Button{Clicked: sync.NewCond(&sync.Mutex{})}

    subscribe := func(c *sync.Cond, fn func()) {
        //var goroutineRunning sync.WaitGroup
        //goroutineRunning.Add(1)
        go func() {
            //goroutineRunning.Done()
            c.L.Lock()
            defer c.L.Unlock()
            c.Wait()
            fn()
        }()
        //goroutineRunning.Wait()
    }

    var clickRegistered sync.WaitGroup
    clickRegistered.Add(3)
    subscribe(button.Clicked, func() {
        fmt.Println("Maximizing window")
        clickRegistered.Done()
    })
    subscribe(button.Clicked, func() {
        fmt.Println("Displaying annoying dialogue box!")
        clickRegistered.Done()
    })
    subscribe(button.Clicked, func() {
        fmt.Println("Mouse clicked.")
        clickRegistered.Done()
    })

    button.Clicked.Broadcast()
    clickRegistered.Wait()
}

我正在关注 concurrency in go 一书中的一些示例,并且我在 subscribe 方法中注释了一些代码语句。有人可以帮忙解释为什么这段代码会死锁吗。

最佳答案

注意:就命名而言,clickRegistered 不符合您代码的当前行为。 handlerExecuted 会更准确。


解决死锁的一种方法:

从您的代码开始:https://play.golang.org/p/XEduyON9j59

您可以将一个额外的 waitGroup 或一个 channel 传递给您的 goroutine,以便它们可以向主 goroutine 发出它们正在运行的信号,但实际上您也可以使用条件本身来做到这一点:

    subscribe := func(c *sync.Cond, fn func()) {
        c.L.Lock()  // take the lock synchronously, the lock will be available
                    // again once the goroutine executes 'c.Wait()'
        go func() {
            defer c.L.Unlock()
            c.Wait()
            fn()
        }()
    }

    subscribe(...)
    subscribe(...)
    subscribe(...)

    button.Clicked.L.Lock() // will return only once all subscribers are '.Wait()'ing

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


这是解决死锁的另一种方法,使用 Waitgroup 让 goroutines 发出它们正在运行的信号:
https://play.golang.org/p/LSM72HBmo0M

订阅的运行方式可能感觉更“并发”;但是,您会注意到,要知道它们实际上正在运行它们的 .Wait() 指令,唯一直接的方法仍然是获取条件锁。

关于go - 使用 sync.Cond 时所有 go routines 都处于休眠状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69605585/

相关文章:

go - 由结构包装的 sql.DB 无法在实例中调用方法

postgresql - 串行(自动递增)主键的标签

java - 可重入锁实现细节

json.Marshal(struct) 返回 "{}"

go - 如何使用golang过滤给定数据中的元素?

ios - 未收到来自 GCM CCS 的 delivery_receipt_notification

c# - .Net 应用程序中并发问题的最佳实践

Java 并发 JDK 1.6 : Busy wait does better than signalling? Effective Java #51

java - 在 Go 中写 int32 原子操作?

c# - 防止在 ASP.NET 中与 ADO.NET 并发执行存储过程