2 回答

TA貢獻1804條經驗 獲得超8個贊
我認為這就是你需要的:
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")
}

TA貢獻1773條經驗 獲得超3個贊
目前尚不清楚您是否可以控制這些子進程。如果是這樣,您可以考慮使用以下 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?。┗騍IGHUP由于其他原因需要處理。
現在,如果您對子進程的代碼沒有任何控制權……您可以嘗試通過搜索所有子進程來從 Go 應用程序中殺死每個子進程,一個一個地殺死它們,然后殺死父進程。但是,您總是會遇到無法避免的競爭條件,除非您可以阻止整個子樹創建新進程。如果你能做到這一點,那么只需注冊所有這些孩子的PID并一個一個地殺死他們。
當然,如果能建個群就更好了。像上面的 SIGHUP 一樣,殺死一個組的所有成員是由內核完成的,它不會錯過任何進程。
- 2 回答
- 0 關注
- 433 瀏覽
添加回答
舉報