如题,比如代码这样的:
func command(command string, writer io.Writer, notify chan struct{}) { r, w := io.Pipe() cmd := exec.Command("bash") cmd.Dir = "/data" cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} # 这个还不兼容 windows cmd.Stdin = r stdout, _ := cmd.StdoutPipe() stderr, _ := cmd.StderrPipe() defer stdout.Close() defer stderr.Close() cmd.Start() go trans(stdout, writer) // iocopy go trans(stderr, writer) go func() { <-notify fmt.Println(cmd.Process.Kill()) w.Close() }() fmt.Fprint(w, command) w.Close() cmd.Wait() }如果执行 yarn build 会执行一个 nodejs 的构建,但是当 notify 通知后,bash 进程退出了。nodejs 进程僵尸了。怎么保证所有由 bash 开启的所有子进程都被关闭(哪怕强制退出)?
最后的解决方法与 go 没有关系,这个问题似乎是 git 的问题,我起了一个定时任务,定期检查 fefunct 的进程项,然后通过调用 wait 强行把它们从进程表中删除。
POSIX(Linux 除外)似乎没有通用方法。杀进程组的话,子进程可以创建新的进程组来避免。杀进程树的话,子进程可以 fork 两次来脱离进程树。
Linux 可以用 PID namespace 来实现,当一个 PID namespace 里面的“init”进程退出后,其他进程都会被停止。
Windows 可以用 Job Object 实现。