sync.Cond 无法在多个 Goroutines 中正常工作

问题描述 投票:0回答:1

仅当

sync.Cond
执行广播时,我才尝试在多个 go 例程中进行打印,但 go 例程陷入僵局。有什么方法可以改进下面的代码,有什么方法可以确定为什么这段代码会死锁?

package main

import (
    "fmt"
    "sync"
)

type Button struct {
    Clicked *sync.Cond
}

func subscribe(cond *sync.Cond, btnMessage string, wg *sync.WaitGroup) {
    defer wg.Done()
    cond.L.Lock()
    defer cond.L.Unlock()

    cond.Wait()
    fmt.Println(btnMessage)
}

func test6() {
    var wg sync.WaitGroup

    button := Button{
        Clicked: sync.NewCond(&sync.Mutex{}),
    }

    wg.Add(3)
    go subscribe(button.Clicked, "Button 1", &wg)
    go subscribe(button.Clicked, "Button 2", &wg)
    go subscribe(button.Clicked, "Button 3", &wg)

    // Start the goroutines before broadcasting
    button.Clicked.Broadcast()

    wg.Wait()
}

func main() {
    test6()
}

我收到以下死锁错误

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x466df7?)
    /nix/store/akhjsmrrsakcnj8x3xgygvizhccbyn0v-go-1.19.3/share/go/src/runtime/sema.go:62 +0x25
sync.(*WaitGroup).Wait(0x405399?)
    /nix/store/akhjsmrrsakcnj8x3xgygvizhccbyn0v-go-1.19.3/share/go/src/sync/waitgroup.go:139 +0x52
main.test6()
    /home/runner/concurrency-in-go/main.go:36 +0x199
main.main()
    /home/runner/concurrency-in-go/main.go:40 +0x17

goroutine 6 [sync.Cond.Wait]:
sync.runtime_notifyListWait(0xc000108050, 0x1)
    /nix/store/akhjsmrrsakcnj8x3xgygvizhccbyn0v-go-1.19.3/share/go/src/runtime/sema.go:517 +0x14c
sync.(*Cond).Wait(0x0?)
    /nix/store/akhjsmrrsakcnj8x3xgygvizhccbyn0v-go-1.19.3/share/go/src/sync/cond.go:70 +0x8c
main.subscribe(0xc000108040, {0x49962f, 0x8}, 0x0?)
    /home/runner/concurrency-in-go/main.go:17 +0xbb
created by main.test6
    /home/runner/concurrency-in-go/main.go:29 +0xdb

goroutine 7 [sync.Cond.Wait]:
sync.runtime_notifyListWait(0xc000108050, 0x2)
    /nix/store/akhjsmrrsakcnj8x3xgygvizhccbyn0v-go-1.19.3/share/go/src/runtime/sema.go:517 +0x14c
sync.(*Cond).Wait(0x0?)
    /nix/store/akhjsmrrsakcnj8x3xgygvizhccbyn0v-go-1.19.3/share/go/src/sync/cond.go:70 +0x8c
main.subscribe(0xc000108040, {0x499637, 0x8}, 0x0?)
    /home/runner/concurrency-in-go/main.go:17 +0xbb
created by main.test6
    /home/runner/concurrency-in-go/main.go:30 +0x12f

goroutine 8 [sync.Cond.Wait]:
sync.runtime_notifyListWait(0xc000108050, 0x0)
    /nix/store/akhjsmrrsakcnj8x3xgygvizhccbyn0v-go-1.19.3/share/go/src/runtime/sema.go:517 +0x14c
sync.(*Cond).Wait(0x0?)
    /nix/store/akhjsmrrsakcnj8x3xgygvizhccbyn0v-go-1.19.3/share/go/src/sync/cond.go:70 +0x8c
main.subscribe(0xc000108040, {0x49963f, 0x8}, 0x0?)
    /home/runner/concurrency-in-go/main.go:17 +0xbb
created by main.test6
    /home/runner/concurrency-in-go/main.go:31 +0x185
exit status 2
multithreading go concurrency synchronization goroutine
1个回答
0
投票

在你的 goroutine 初始化之前你就已经开始广播了。所以你最终会广播然后再次等待。如果您在主线程中插入睡眠,您可以看到它开始工作。

游乐场正在运行

只有当满足某些条件时,你才应该在 goroutine 中等待。根据您的实际用例,您可能会考虑不同的同步原语。

© www.soinside.com 2019 - 2024. All rights reserved.