gpt4 book ai didi

go - 对goroutines中的延迟感到困惑

转载 作者:行者123 更新时间:2023-12-01 20:27:06 26 4
gpt4 key购买 nike

我遇到了以下代码段,这些代码段演示了sync.Cond中的“广播”功能。摘录如下:

package main

import (
"fmt"
"sync"
)

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()
}

输出如下:
Mouse clicked.
Maximizing window.
Displaying annoying dialogue box!

我更改了订阅中的goroutine,以在goroutine完成执行后推迟对gorroutineRunning WaitGroup 的“完成”调用。我的想法是,只有在执行go例程后, WaitGroup 才应递减。所以我将代码更改如下:
package main

import (
"fmt"
"sync"
)

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

....
}

加上延后,我会感到以下 panic :
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc0000b6028)
/usr/local/go/src/runtime/sema.go:56 +0x42
sync.(*WaitGroup).Wait(0xc0000b6020)
/usr/local/go/src/sync/waitgroup.go:130 +0x64
main.main.func1(0xc00009e040, 0xc0000b4030)
/Users/go/concur/button.go:24 +0x91
main.main()
/Users/go/concur/button.go:29 +0xf4

goroutine 18 [sync.Cond.Wait]:
runtime.goparkunlock(...)
/usr/local/go/src/runtime/proc.go:310
sync.runtime_notifyListWait(0xc00009e050, 0x0)
/usr/local/go/src/runtime/sema.go:510 +0xf8
sync.(*Cond).Wait(0xc00009e040)
/usr/local/go/src/sync/cond.go:56 +0x9d
main.main.func1.1(0xc0000b6020, 0xc00009e040, 0xc0000b4030)
/Users/go/concur/button.go:21 +0xbb
created by main.main.func1
/Users/go/concur/button.go:17 +0x83
exit status 2

有人可以引导我理解为什么添加延迟会导致代码崩溃吗?

最佳答案

当goroutine开始运行时,原始代码将释放 WaitGroup 。当subscribe函数返回时,goroutine仍处于 Activity 状态。

当您将其更改为defer goroutineRunning.Done()时,goroutine开始,并在c.Wait()处停止,因为它正在等待条件变量的广播。由于goroutine正在等待,因此不调用goroutineRunning.Done,并且subscribe函数在goroutineRunning.Wait处停止。因此,第一次调用subscribe时,它将创建一个等待cond的goroutine,subscribe本身开始在waitgroup中等待。有goroutines(主要程序和一个由订阅开始的程序),都等待某个事件发生,但是没有其他goroutines在运行以使该事件发生,因此出现了死锁。

关于go - 对goroutines中的延迟感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60049459/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com