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

Van*_*ota 5 unix signals go

当有代码时:

package main

import (
    "os"
    "os/signal"
)

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

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

但:

package main

func main() {
    sig := make(chan int, 1)
    <-sig
}
Run Code Online (Sandbox Code Playgroud)

抛出这个错误:

fatal error: all goroutines are asleep - deadlock!

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

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

我的怀疑有点正确吗?如果是这样,运行时如何与其他通道类型不同地处理它?

谢谢!

Ole*_*leg 6

您遇到了死锁,因为尝试从通道接收消息,但不存在其他正在运行的非发送者的 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并检查从运行时包调用了哪个函数。然后跳转到该文件并投入时间来了解实现。您会发现与其他事物相比,通道的实现简单而简单

希望能帮助到你!