亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

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

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

Go
守候你守候我 2021-11-08 19:29:34
我有一種情況,我需要在一段時間后終止一個進程。我開始這個過程,然后: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)殺死主進程和孫進程,但不起作用。有沒有其他方法可以終止進程。
查看完整描述

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")

}


查看完整回答
反對 回復 2021-11-08
?
慕容3067478

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 一樣,殺死一個組的所有成員是由內核完成的,它不會錯過任何進程。


查看完整回答
反對 回復 2021-11-08
  • 2 回答
  • 0 關注
  • 433 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號