gpt4 book ai didi

go - 在 Go 中收到 SIGINT 时是否调用延迟函数?

转载 作者:IT王子 更新时间:2023-10-29 01:23:08 26 4
gpt4 key购买 nike

对于下面的代码片段,在收到 ^C 时不会进行延迟调用。清理是否有可能引入竞争条件?如果是,什么是接收中断时更好的清理模式?

  func fn() {
// some code
defer cleanup()
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)

// Block until a signal is received.
_ = <-c
cleanup()
}
for {
// Infinite loop. Returns iff an error is encountered in the
// body
}
}

最佳答案

请注意,如果您使用 signal.Notify()“安装”您的信号 channel ,默认行为将被禁用。这意味着如果您这样做,fn() 函数中的 for 循环将不会被中断,它将继续运行。

因此,当您在注册的 channel 上收到一个值时,您必须终止 for 循环,以便进行“干净”的清理。否则,cleanup() 应该释放的资源可能仍在 for 中使用,很可能导致错误或 panic 。

执行此操作后,您甚至不必手动调用 cleanup(),因为从 fn() 返回将正确运行延迟函数。

这是一个例子:

var shutdownCh = make(chan struct{})

func fn() {
defer cleanup()

go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
close(shutdownCh)
}()

for {
select {
case <-shutdownCh:
return
// Other cases might be listed here..
default:
}
time.Sleep(time.Millisecond)
}
}

当然,上面的例子并不能保证应用程序终止。您应该有一些代码来监听 shutdownCh 并终止应用程序。此代码还应等待所有 goroutine 正常完成。为此,您可以使用 sync.WaitGroup : 当你启动一个应该在退出时等待的 goroutine 时,给它加 1,并在这样的 goroutine 完成时调用 WaitGroup.Done()

此外,由于在真实应用中可能有很多这样的信号处理,信号处理应移至“中央”位置,而不是在每个位置都进行。

这是一个完整的例子,如何做到这一点:

var shutdownCh = make(chan struct{})
var wg = &sync.WaitGroup{}

func main() {
wg.Add(1)
go func() {
defer wg.Done()
fn()
}()

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
close(shutdownCh)
wg.Wait()
}

func fn() {
defer cleanup()
for {
select {
case <-shutdownCh:
return
// Other cases might be listed here..
default:
}
fmt.Println("working...")
time.Sleep(time.Second)
}
}

func cleanup() {
fmt.Println("cleaning up...")
}

这是上述应用程序的示例输出,在启动后按 CTRL+C 3 秒时:

working...
working...
working...
^Ccleaning up...

关于go - 在 Go 中收到 SIGINT 时是否调用延迟函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50406639/

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