簡體   English   中英

你如何在 Go 代碼超時時殺死一個進程及其子進程?

[英]How do you kill a process and its children on a timeout in Go code?

我有一種情況,我需要在一段時間后終止一個進程。 我開始這個過程,然后:

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)

殺死主進程和孫進程,但不起作用。 有沒有其他方法可以終止進程。

我認為這就是你需要的:

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 {
    return err
}

// buffered chan is important so the goroutine does't
// get blocked and stick around if the function returns
// after the timeout
done := make(chan error, 1)

go func() {
    done <- cmd.Wait()
}()

select {
case err := <-done:
    // this will be nil if no error
    return err
case <-time.After(time.Second):
    // We created a process group above which we kill here.
    pgid, err := syscall.Getpgid(cmd.Process.Pid)
    if err != nil {
        return err
    }
    // note the minus sign
    if err := syscall.Kill(-pgid, 15); err != nil {
        return err
    }
    return fmt.Errorf("Timeout")
}

目前尚不清楚您是否可以控制這些子進程。 如果是這樣,您可以考慮使用以下 Linux 功能(您也沒有說明它是否特定於操作系統)。

這行代碼要求內核在父母去世時向孩子發送一個 SIGHUP。 這樣你的 Go 進程就可以殺死父進程,它會自動殺死所有的子進程。 不僅如此,它永遠不會失敗! 內核在那個上非常好。

prctl(PR_SET_PDEATHSIG, SIGHUP);

當然,如果你這樣做,就會出現競爭條件。 也就是說,當孩子調用這個prctl()函數時,父母可能已經死了,在這種情況下孩子需要立即退出。

if(getppid() != parent_pid)
{
    exit(1);
}

所以避免競爭條件的完整代碼是:

// must happen before the fork() call
const pid_t parent_pid = getpid();

const pid_t child_pid = fork();

if(child_pid != 0)
{
    // fork() failed (child_pid == -1) or worked (an actual PID)
    ...
    return;
}

prctl(PR_SET_PDEATHSIG, SIGHUP);

if(getppid() != parent_pid)
{
    exit(1);
}

注意:對於這種情況,習慣上使用SIGHUP 您可能還想考慮其他信號,特別是如果孩子處理管道/套接字(在這種情況下您可能會忽略SIGHUP !)或由於其他原因需要處理SIGHUP

現在,如果您對子進程的代碼沒有任何控制權……您可以嘗試通過搜索所有子進程來從 Go 應用程序中殺死每個子進程,一個一個地殺死它們,然后殺死父進程。 但是,您總是會遇到無法避免的競爭條件,除非您可以阻止整個子樹創建新進程。 如果你能做到這一點,那么只需注冊所有這些孩子的PID並一個一個地殺死他們。

當然,如果能建個群就更好了。 像上面的 SIGHUP 一樣,殺死一個組的所有成員是由內核完成的,它不會錯過任何進程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM