我的代码是这样的:
var lock sync.Mutex
func DoSomething() {
lock.Lock()
go func() {
defer lock.Unlock()
// Code here
}()
}
func Wait() {
lock.Lock()
lock.Unlock()
}
我需要
Wait()
,因为有时我必须在 DoSomething()
或 panic
之前调用 sys.Exit
。所以,在这些情况下,我需要它来完成。
只要我一次只调用
DoSomething()
一次,它就可以正常工作,但是当然,如果调用两次,第二个会在调用 goroutine 之前等待。
DoSomething() // returns immediately
DoSomething() // waits until the first one finishes to return
如果我将锁放在 Goroutine 内部,那么
Wait()
在 Goroutine 启动之前就会被调用。
func DoSomething() {
go func() {
lock.Lock()
defer lock.Unlock()
// Code here
}()
}
DoSomething()
Wait() // this finishes before the goroutine even starts
我在
sync
中尝试了一些其他的东西,但还没有找到有效的东西。
我什至尝试将 goroutine 从
DoSomething
中取出并像 go DoSomething()
那样调用它,但我也无法让它工作。
免责声明:我仍在学习围棋。我不能 100% 确定这是惯用的方法(双关语)。
这个解决方案的想法是:我们不直接调用方法,而是:
把它们放在一起,我们得到这样的结果:
package main
import "fmt"
// This is the channel used by doSomething() to be notified when it
var doSomethingChannel = make(chan chan<- interface{})
// This is the channel we expose as interface to the outside so we can trigger "doSomething" to... do something
func DoSomethingChannel() chan<- chan<- interface{} {
return doSomethingChannel
}
func doSomething() {
for {
back := <- doSomethingChannel
// code goes here
fmt.Println("[GOROUTINE] Executing")
// if the back-channel is set, i.e. if the caller wants to be informed, write a signal on the back-channel
if back != nil {
back<- struct{}{}
}
}
}
func main() {
go doSomething()
for i := 0; i < 11; i += 1 {
// if i is even, we want to wait, otherwise we do not want to wait
var back chan interface{} = nil
if i % 2 == 0 {
back = make(chan interface{})
fmt.Printf("[CALLER] Waiting for execution %d\n", i)
} else {
fmt.Printf("[CALLER] Calling for execution %d, will not wait\n", i)
}
// send the back-channel to the DoSomethingChannel, this will trigger doSomething()
DoSomethingChannel() <- back
if back != nil {
// Wait if back-channel was used
<-back
fmt.Printf("[CALLER] %d has been done\n", i)
}
}
}
go.dev
演示