提问人:cool_fire 提问时间:10/22/2023 更新时间:10/22/2023 访问量:51
同步。电导率在多个 goroutine 中无法正常唤醒
sync.Cond not woking properly with multiple goroutines
问:
我尝试仅在广播时打印多个 go 例程,但 go 例程死锁。有没有办法改进下面的代码,有什么方法可以确定为什么这个代码是死锁的?sync.Cond
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
答:
3赞
Eli Davis
10/22/2023
#1
你甚至在你的 goroutines 初始化之前就已经广播了。所以你最终会广播,然后再次等待。如果你在主线程中插入一个睡眠,你可以看到它开始工作。
只有当满足某些条件时,您才应该在 goroutine 中等待。根据您的实际用例,您可以考虑使用不同的同步原语。
评论
1赞
Kaveh Shahbazian
10/23/2023
为了证明这一点,如果我们等待 goroutines 启动,然后广播,它就会起作用。go.dev/play/p/VP9f_LvIBXB
0赞
cool_fire
10/23/2023
感谢您的解释,我明白为什么它不起作用,感谢您的努力
评论