process - golang 重新启动的父进程没有收到 SIGINT

标签 process go child-process kill-process sigint

我正在编写一个小程序来管理其他进程的重启。

基本上,当应用程序进程启动时(称为 A),它会生成一个新进程(称为 D),该进程具有一个简单的 HTTP 服务器。当 D 收到 http 请求时,它会杀死 A 并重新启动它。

问题是,A 现在不响应 CTRL-C,我不确定为什么。这可能是一些简单的事情,也可能是我不太了解进程、终端和信号之间的关系。但它在具有相同标准输入/标准输出/标准错误的同一终端中运行。下面是演示此行为的完整程序。

package main

import (
    "flag"
    "log"
    "net/http"
    "os"
    "os/exec"
    "strconv"
    "time"
)

/*
    Running this program starts an app (repeatdly prints 'hi') and spawns a new process running a simple HTTP server
    When the server receives a request, it kills the other process and restarts it.
    All three processes use the same stdin/stdout/stderr.
    The restarted process does not respond to CTRL-C :(
*/

var serv = flag.Bool("serv", false, "run server")

// run the app or run the server
func main() {
    flag.Parse()
    if *serv {
        runServer()
    } else {
        runApp()
    }
}

// handle request to server
// url should contain pid of process to restart
func handler(w http.ResponseWriter, r *http.Request) {
    pid, err := strconv.Atoi(r.URL.Path[1:])
    if err != nil {
        log.Println("send a number...")
    }
    // find the process
    proc, err := os.FindProcess(pid)
    if err != nil {
        log.Println("can't find proc", pid)
        return
    }
    // terminate the process
    log.Println("Terminating the process...")
    err = proc.Signal(os.Interrupt)
    if err != nil {
        log.Println("failed to signal interupt")
        return
    }
    // restart the process
    cmd := exec.Command("restarter")
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    if err := cmd.Start(); err != nil {
        log.Println("Failed to restart app")
        return
    }
    log.Println("Process restarted")
}

// run the server.
// this will only work the first time and that's fine
func runServer() {
    http.HandleFunc("/", handler)
    if err := http.ListenAndServe(":9999", nil); err != nil {
        log.Println(err)
    }
}

// the app prints 'hi' in a loop
// but first it spawns a child process which runs the server
func runApp() {
    cmd := exec.Command("restarter", "-serv")
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    if err := cmd.Start(); err != nil {
        log.Println(err)
    }

    log.Println("This is my process. It goes like this")
    log.Println("PID:", os.Getpid())
    for {
        time.Sleep(time.Second)
        log.Println("hi again")
    }
}

该程序需要安装。为方便起见,您可以使用 go get github.com/ebuchman/restarter 获取它.

使用 restarter 运行程序.它应该打印它的进程 ID。那么curl http://localhost:9999/<procid>启动重启。新进程现在不会响应 CTRL-C。为什么?我错过了什么?

最佳答案

这与 Go 没有任何关系。您从终端 shell 启动进程 A。进程 A 启动进程 D(不确定 B 发生了什么,但没关系)。进程 D 杀死进程 A。现在您的 shell 看到它启动的进程已经退出,因此 shell 准备监听另一个命令。进程 D 启动进程 A 的另一个副本,但 shell 对此一无所知。当您键入 ^C 时,shell 将处理它。如果您运行另一个程序,shell 将安排 ^C 转到该程序。 shell 对您的进程 A 的副本一无所知,因此它永远不会将 ^C 指向该进程。

关于process - golang 重新启动的父进程没有收到 SIGINT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28388758/

相关文章:

linux - 终端中的 ps -aux 到底在做什么?

go - Go 的 bufio.Scanner 中的 "Scan advances the Scanner to the next token"是什么意思?

process - 从进程 stdout 中读取,而不是一次将其全部放入内存

go - 无法获取通过反射调用的方法的返回字符串值

json - 如何在 GJSON 中循环 slice

javascript - 是否可以在 node.js 中创建子进程,当它们的父进程退出时它们不会退出?

macos - 在 bash 脚本中重定向多个子进程的输出

javascript - 子进程何时终止

android - Android中进程、 Activity 、线程和任务之间的区别

c - 管道和流程