首頁 >後端開發 >Golang >考慮到潛在的作業系統不一致,如何可靠地超時並終止 Go 中的子進程?

考慮到潛在的作業系統不一致,如何可靠地超時並終止 Go 中的子進程?

DDD
DDD原創
2024-12-02 15:51:11302瀏覽

How Can I Reliably Timeout and Terminate Child Processes in Go, Considering Potential OS Inconsistencies?

Go 中的進程超時和子進程終止

在Go 中,超時和終止子進程的能力對於維護系統穩定性至關重要。確保應用程式的響應能力。然而,進程終止可能會出現不一致,如以下程式碼所示:

func() {
    var output bytes.Buffer
    cmd := exec.Command("Command", args...)
    cmd.Dir = filepath.Dir(srcFile)
    cmd.Stdout, cmd.Stderr = &output, &output
    if err := cmd.Start(); err != nil {
        return err
    }
    defer time.AfterFunc(time.Second*2, func() {
        fmt.Printf("Nobody got time fo that\n")
        if err := cmd.Process.Signal(syscall.SIGKILL); err != nil {
            fmt.Printf("Error:%s\n", err)
        }
        fmt.Printf("It's dead Jim\n")
    }).Stop()
    err := cmd.Wait()
    fmt.Printf("Done waiting\n")
}()

在此程式碼中,超時機制似乎有問題:雖然它正確列印“It's dead Jim”,但它無法列印“完成等待”並讓子進程繼續運行。

根本原因:SIGKILL限制

罪魁禍首在於使用 cmd.Process.Signal(syscall.SIGKILL) 來終止進程。在某些情況下,SIGKILL 可能不足以殺死子進程。根本原因是現代作業系統為每個行程維護單獨的進程組。當一個群組中的一個進程嘗試使用 SIGKILL 終止另一個群組中的另一個進程時,訊號可能無法有效傳遞。

解決方案:使用負進程組 ID

為了規避此問題,解決方案涉及將負進程組 ID (-pgid) 與 syscall.Kill 結合使用。透過在進程組 ID 前加上減號,訊號將傳送到整個進程組而不是單一進程。這可確保子程序也被終止:

cmd := exec.Command( some_command )
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
cmd.Start()

pgid, err := syscall.Getpgid(cmd.Process.Pid)
if err == nil {
    syscall.Kill(-pgid, 15)  // note the minus sign
}

cmd.Wait()

注意事項和平台注意事項

需要注意的是,此解決方案可能無法跨所有作業系統移植。操作進程組的能力在不同平台之間有所不同。雖然此解決方案經過測試並可在 macOS Yosemite 上運行,但其行為在其他平台(例如 Windows 或某些 Linux 版本)上可能會有所不同。

以上是考慮到潛在的作業系統不一致,如何可靠地超時並終止 Go 中的子進程?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn