猿问

你如何在 Go 代码超时时杀死一个进程及其子进程?

我有一种情况,我需要在一段时间后终止一个进程。我开始这个过程,然后:


case <-time.After(timeout):

        if err := cmd.Process.Kill(); err != nil {

            return 0, fmt.Errorf("Failed to kill process: %v", err)

        }

杀死进程。但它只会杀死父进程,而不是主进程启动的 5-10 个子进程。我还尝试创建一个进程组,然后执行以下操作:


syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)

杀死主进程和孙进程,但不起作用。有没有其他方法可以终止进程。


守候你守候我
浏览 363回答 2
2回答

胡说叔叔

我认为这就是你需要的:cmd := exec.Command(command, arguments...)// This sets up a process group which we kill later.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}if err := cmd.Start(); err != nil {&nbsp; &nbsp; return err}// buffered chan is important so the goroutine does't// get blocked and stick around if the function returns// after the timeoutdone := make(chan error, 1)go func() {&nbsp; &nbsp; done <- cmd.Wait()}()select {case err := <-done:&nbsp; &nbsp; // this will be nil if no error&nbsp; &nbsp; return errcase <-time.After(time.Second):&nbsp; &nbsp; // We created a process group above which we kill here.&nbsp; &nbsp; pgid, err := syscall.Getpgid(cmd.Process.Pid)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; // note the minus sign&nbsp; &nbsp; if err := syscall.Kill(-pgid, 15); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; return fmt.Errorf("Timeout")}

慕容3067478

目前尚不清楚您是否可以控制这些子进程。如果是这样,您可以考虑使用以下 Linux 功能(您也没有说明它是否特定于操作系统)。这行代码要求内核在父母去世时向孩子发送一个 SIGHUP。这样你的 Go 进程就可以杀死父进程,它会自动杀死所有的子进程。不仅如此,它永远不会失败!内核在那个上非常好。prctl(PR_SET_PDEATHSIG, SIGHUP);当然,如果你这样做,就会出现竞争条件。也就是说,当孩子调用这个prctl()函数时,父母可能已经死了,在这种情况下,孩子需要立即退出。if(getppid() != parent_pid){&nbsp; &nbsp; exit(1);}所以避免竞争条件的完整代码是:// must happen before the fork() callconst pid_t parent_pid = getpid();const pid_t child_pid = fork();if(child_pid != 0){&nbsp; &nbsp; // fork() failed (child_pid == -1) or worked (an actual PID)&nbsp; &nbsp; ...&nbsp; &nbsp; return;}prctl(PR_SET_PDEATHSIG, SIGHUP);if(getppid() != parent_pid){&nbsp; &nbsp; exit(1);}注意:通常SIGHUP用于这种情况。您可能还想考虑其他信号,特别是如果孩子处理管道/套接字(在这种情况下您可能会忽略SIGHUP!)或SIGHUP由于其他原因需要处理。现在,如果您对子进程的代码没有任何控制权……您可以尝试通过搜索所有子进程来从 Go 应用程序中杀死每个子进程,一个一个地杀死它们,然后杀死父进程。但是,您总是会遇到无法避免的竞争条件,除非您可以阻止整个子树创建新进程。如果你能做到这一点,那么只需注册所有这些孩子的PID并一个一个地杀死他们。当然,如果能建个群就更好了。像上面的 SIGHUP 一样,杀死一个组的所有成员是由内核完成的,它不会错过任何进程。
随时随地看视频慕课网APP

相关分类

Go
我要回答