Go 内部如何处理 os.Signal 通道?

How an os.Signal channel is handled internally in Go?

当有代码时:

package main

import (
    "os"
    "os/signal"
)

func main() {
    sig := make(chan os.Signal, 1)
    signal.Notify(sig)
    <-sig
}

运行没有问题,当然会阻塞,直到您发送中断程序的信号。

但是:

package main

func main() {
    sig := make(chan int, 1)
    <-sig
}

抛出此错误:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
    /home/user/project/src/main.go:5 +0x4d
exit status 2

虽然我理解为什么从 int 频道读取会导致死锁,但我只是怀疑 os.Signal 不会,因为它的通道可能会受到来自 "the outside" 的写入,嗯, 它处理信号,它们来自程序外部。

我的怀疑是不是有点正确?如果是这样,运行时处理此问题的方式与其他通道类型有何不同?

谢谢!

您遇到了死锁,因为尝试从通道接收消息但不存在其他非发送方的 goroutine 运行。同时调用 signal.Notify 在后台启动 watchSignalLoop() goroutine,您可以在此处验证实现细节 https://golang.org/src/os/signal/signal.go.

频道不关心元素类型,除非你的元素类型大于 64kB(严格来说,还有其他细微差别,请检查实现)。

不要猜测运行时是如何工作的,进行研究。例如,您可以检查调用 make(chan int) 时会发生什么。您可以执行 go tool compile -S main.go | grep main.go:line of make chan 并检查从运行时包中调用了哪个函数。然后跳转到这个文件并花时间了解实现。与其他事物相比,您会发现通道的实现简单明了

希望对您有所帮助!