我有一些代码,在Go(golang)中,有几个不同的线程运行一个单独的可执行文件。我想确保如果用户在Go中杀死我的进程,我有办法杀死我调用的可执行程序,有办法做到吗?
s2j5cfk01#
确保子进程被杀死的唯一方法是在同一个进程组中启动它,并将进程组作为一个整体杀死,或者在syscall.SetProcAttr中设置Pdeadthsig。您可以为常见的信号(如SIG_INT和SIG_TERM)设置一个信号处理程序,并在退出前杀死子进程,但由于您无法捕获SIG_KILL,因此通常不值得这样做。参见:其他goroutine中的Panic没有停止子进程
syscall.SetProcAttr
Pdeadthsig
SIG_INT
SIG_TERM
SIG_KILL
cmd := exec.Command("./long-process") cmd.SysProcAttr = &syscall.SysProcAttr{ Pdeathsig: syscall.SIGTERM, }
fwzugrvs2#
如果你在Windows上,你可能会发现这个片段很有帮助:
package main import ( "os" "os/exec" "unsafe" "golang.org/x/sys/windows" ) // We use this struct to retreive process handle(which is unexported) // from os.Process using unsafe operation. type process struct { Pid int Handle uintptr } type ProcessExitGroup windows.Handle func NewProcessExitGroup() (ProcessExitGroup, error) { handle, err := windows.CreateJobObject(nil, nil) if err != nil { return 0, err } info := windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION{ BasicLimitInformation: windows.JOBOBJECT_BASIC_LIMIT_INFORMATION{ LimitFlags: windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, }, } if _, err := windows.SetInformationJobObject( handle, windows.JobObjectExtendedLimitInformation, uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info))); err != nil { return 0, err } return ProcessExitGroup(handle), nil } func (g ProcessExitGroup) Dispose() error { return windows.CloseHandle(windows.Handle(g)) } func (g ProcessExitGroup) AddProcess(p *os.Process) error { return windows.AssignProcessToJobObject( windows.Handle(g), windows.Handle((*process)(unsafe.Pointer(p)).Handle)) } func main() { g, err := NewProcessExitGroup() if err != nil { panic(err) } defer g.Dispose() cmd := exec.Command("notepad.exe", "noname") if err := cmd.Start(); err != nil { panic(err) } if err := g.AddProcess(cmd.Process); err != nil { panic(err) } if err := cmd.Wait(); err != nil { panic(err) } }
原文链接:https://gist.github.com/hallazzang/76f3970bfc949831808bbebc8ca15209
lf5gs5x23#
一种可能的策略是将正在运行的进程列表保存在一个全局数组var childProcesses = make([]*os.Process, 0)中,并在每次启动一个进程时添加到该数组中。拥有自己的Exit功能。请确保在代码中的任何地方都不要调用os.Exit,而是始终调用自己的Exit函数。您的退出函数将杀死所有的childProcesses
var childProcesses = make([]*os.Process, 0)
Exit
os.Exit
childProcesses
for _, p := range childProcesses { p.Kill() }
处理信号,使它们通过您自己的退出函数,例如在初始化期间这样做(在主函数顶部附近)
sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT) goUnsafe(func() { var signal = <-sigs log.Println("Got Signal", signal) Exit(0) })
qvtsj1bj4#
建议使用unix.prctl。
flag := unix.SIGHUP if err := unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(flag), 0, 0, 0); err != nil { return }
下面是一个详细的例子,new.go作为子进程,main.go作为父进程。
//new.go package main func main() { flag := unix.SIGHUP if err := unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(flag), 0, 0, 0); err != nil { return } f, _ := os.Create("./dat2") defer f.Close() i := 0 for { n3, _ := f.WriteString("writes " + string(i) + "\n") fmt.Printf("wrote %d bytes\n", n3) f.Sync() i += 2 time.Sleep(2 * time.Second) } for { n3, _ := f.WriteString("newwrites\n") fmt.Printf("wrote %d bytes\n", n3) f.Sync() time.Sleep(2 * time.Second) } } //main.go package main import "os/exec" func main() { commandA := exec.Command("./new") commandA.Start() commandB := exec.Command("./new") commandB.Start() for { } }
5lwkijsr5#
我有一些代码,在Go(golang)中,有几个不同的线程运行一个单独的可执行文件。我想确保如果用户在Go中杀死我的进程,我有办法杀死我调用的可执行程序,有办法做到吗?我不清楚你所说的“不同的线程运行”是什么意思。我假设:
在这个意义上,我们正在讨论创建一个进程组,并确保当您杀死一个进程时,该组中的所有其他进程也必须停止。此机制取决于操作系统。在当前版本中,有两种可能性(请参见软件包x/sys):
*Unix:即将setpgid(2)*Windows:大约是CreateProcess。请参阅MS Windows documentation CreateProcess。必须传递CREATE_NEW_PROCESS_GROUP标志(see)
setpgid(2)
CreateProcess
CREATE_NEW_PROCESS_GROUP
5条答案
按热度按时间s2j5cfk01#
确保子进程被杀死的唯一方法是在同一个进程组中启动它,并将进程组作为一个整体杀死,或者在
syscall.SetProcAttr
中设置Pdeadthsig
。您可以为常见的信号(如
SIG_INT
和SIG_TERM
)设置一个信号处理程序,并在退出前杀死子进程,但由于您无法捕获SIG_KILL
,因此通常不值得这样做。参见:其他goroutine中的Panic没有停止子进程
fwzugrvs2#
如果你在Windows上,你可能会发现这个片段很有帮助:
原文链接:https://gist.github.com/hallazzang/76f3970bfc949831808bbebc8ca15209
lf5gs5x23#
一种可能的策略是将正在运行的进程列表保存在一个全局数组
var childProcesses = make([]*os.Process, 0)
中,并在每次启动一个进程时添加到该数组中。拥有自己的
Exit
功能。请确保在代码中的任何地方都不要调用os.Exit
,而是始终调用自己的Exit
函数。您的退出函数将杀死所有的childProcesses
处理信号,使它们通过您自己的退出函数,例如在初始化期间这样做(在主函数顶部附近)
qvtsj1bj4#
建议使用unix.prctl。
下面是一个详细的例子,new.go作为子进程,main.go作为父进程。
5lwkijsr5#
我有一些代码,在Go(golang)中,有几个不同的线程运行一个单独的可执行文件。我想确保如果用户在Go中杀死我的进程,我有办法杀死我调用的可执行程序,有办法做到吗?
我不清楚你所说的“不同的线程运行”是什么意思。我假设:
在这个意义上,我们正在讨论创建一个进程组,并确保当您杀死一个进程时,该组中的所有其他进程也必须停止。此机制取决于操作系统。
在当前版本中,有两种可能性(请参见软件包x/sys):
*Unix:即将
setpgid(2)
*Windows:大约是
CreateProcess
。请参阅MS Windows documentation CreateProcess。必须传递CREATE_NEW_PROCESS_GROUP
标志(see)