如果使用exec.Start()创建的进程的父进程被SIGINT杀死,为什么该进程会退出?

6

我在golang中发现了一个奇怪的问题。如果父进程被os.Interrupt信号中断,那么由exec.Start()执行的程序将会退出,而如果父进程以正常方式退出,则子进程不会退出。这两种情况有何区别呢? 例如:

package main

import "fmt"
import "os"
import "time"
import "os/exec"

func main(){
    cmd := exec.Command("sleep", "100000")
    cmd.Env = os.Environ()
    fmt.Println(cmd.Env)
    cmd.Start()

    time.Sleep(1e9*20)
    return
} 

在这种情况下,如果我们没有打断主程序,在20秒后sleep 100000的父进程将会是init进程
2个回答

14

现在的情况是,如果你发送一个进程SIGINT信号(例如os.Interrupt所做的),同一个进程组中的所有进程也会收到该信号(包括子进程) - SIGINT默认会终止一个进程。

但是,如果父进程正常退出,而不是因为SIGINT或类似原因,同一进程组中的进程不会收到任何信号 - 它将继续运行,但会被init进程接管。这不是Go特有的。


1
值得一提的是,在Windows上可以通过cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP}来防止这种行为。在POSIX上,我相信应该使用SetsidSetpgid - AndreKR
1
对于Linux系统,它是这样的:cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true, Pgid: 0} - Arxeiss

0

我认为这是因为你使用了Start而不是Run

Start启动指定的命令,但不等待其完成。

而:

Run启动指定的命令并等待其完成。

因此,当Go(父)进程退出时,Start只会将进程移交给操作系统。


那可能是一个更相关的原因。发表一个答案,我会点赞它 :-) - Intermernet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接