在例行程序开始后立即调用等待组完成?
calling wait group done right after go routine starts?
https://go.dev/play/p/YVYRWSgcp4u
我在《Go Tools and Techniques for Developers 的 Concurrency in Go Tools and Techniques for Developers》中看到这段代码,其中提到了广播的用法,上下文是使用广播来唤醒三个 goroutings。
package main
import (
"fmt"
"sync"
"time"
)
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() // <---- why here?
//fmt.Println("wg already done")
c.L.Lock()
defer c.L.Unlock()
c.Wait()
fn()
//goroutineRunning.Done(), if put here will result in deadlock, why?
}()
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 dialog box!")
clickRegistered.Done()
})
subscribe(button.Clicked, func() {
fmt.Println("Mouse clicked.")
clickRegistered.Done()
})
time.Sleep(time.Second * 3)
button.Clicked.Broadcast()
clickRegistered.Wait()
}
我正在尝试了解订阅部分
subscribe := func(c *sync.Cond, fn func()) {
var goroutineRunning sync.WaitGroup
goroutineRunning.Add(1)
go func() {
goroutineRunning.Done()
//fmt.Println("wg already done")
c.L.Lock()
defer c.L.Unlock()
c.Wait()
fn()
//goroutineRunning.Done()
//fmt.Println("fn executed")
}()
goroutineRunning.Wait()
}
作者说:
Here we define a convenience function that will allow us to register functions to handle signals from a condition. Each handler is run on its own goroutine, and subscribe will not exit until that goroutine is confirmed to be running.
我的理解是应该defer goroutingRunning.Done()
在gorouting里面,这样后面的代码(包括等待Cond和fn()的调用)才有机会
到 运行), 但在这种情况下 goroutingRunning.Done()
似乎必须在 gorouting 的开头,否则会导致死锁错误,但为什么?
这是一种确保subscribe
returns时goroutine已经启动运行ning的机制。当 goroutine 启动时,它会调用 Done
以向等待的调用者发出 goroutine 正在 运行ning 的信号。如果没有这个机制,有可能在订阅的时候returns goroutine还没有被调度
延迟的Done
将不起作用,因为它只会运行一次goroutine returns,并且只有在条件变量发出信号后才会发生。
该方案不保证新的协程锁定互斥体。这个模式是否真的有必要值得商榷。
https://go.dev/play/p/YVYRWSgcp4u
我在《Go Tools and Techniques for Developers 的 Concurrency in Go Tools and Techniques for Developers》中看到这段代码,其中提到了广播的用法,上下文是使用广播来唤醒三个 goroutings。
package main
import (
"fmt"
"sync"
"time"
)
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() // <---- why here?
//fmt.Println("wg already done")
c.L.Lock()
defer c.L.Unlock()
c.Wait()
fn()
//goroutineRunning.Done(), if put here will result in deadlock, why?
}()
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 dialog box!")
clickRegistered.Done()
})
subscribe(button.Clicked, func() {
fmt.Println("Mouse clicked.")
clickRegistered.Done()
})
time.Sleep(time.Second * 3)
button.Clicked.Broadcast()
clickRegistered.Wait()
}
我正在尝试了解订阅部分
subscribe := func(c *sync.Cond, fn func()) {
var goroutineRunning sync.WaitGroup
goroutineRunning.Add(1)
go func() {
goroutineRunning.Done()
//fmt.Println("wg already done")
c.L.Lock()
defer c.L.Unlock()
c.Wait()
fn()
//goroutineRunning.Done()
//fmt.Println("fn executed")
}()
goroutineRunning.Wait()
}
作者说:
Here we define a convenience function that will allow us to register functions to handle signals from a condition. Each handler is run on its own goroutine, and subscribe will not exit until that goroutine is confirmed to be running.
我的理解是应该defer goroutingRunning.Done()
在gorouting里面,这样后面的代码(包括等待Cond和fn()的调用)才有机会
到 运行), 但在这种情况下 goroutingRunning.Done()
似乎必须在 gorouting 的开头,否则会导致死锁错误,但为什么?
这是一种确保subscribe
returns时goroutine已经启动运行ning的机制。当 goroutine 启动时,它会调用 Done
以向等待的调用者发出 goroutine 正在 运行ning 的信号。如果没有这个机制,有可能在订阅的时候returns goroutine还没有被调度
延迟的Done
将不起作用,因为它只会运行一次goroutine returns,并且只有在条件变量发出信号后才会发生。
该方案不保证新的协程锁定互斥体。这个模式是否真的有必要值得商榷。