英文:
I'm trying to "fork off" a background process in Go -- works perfectly on Mac and Linux, but dies when terminal is closed on Windows
问题
考虑以下这个简单的Go程序,它演示了在Go中“分离”后台进程的标准方法。当它运行时,它应该立即将自己发送到后台,在那里它将每秒写入递增的整数到output.txt。它会持续运行,直到你手动终止它。
这个程序在Mac和Linux上运行得很完美,但在Windows上有一个奇怪的行为:它看起来像是工作了,因为我立即获得了一个命令提示符,我的进程确实在后台运行,并将这些整数写入output.txt。然而,当我关闭终端窗口时,后台进程会被终止。
这个问题在标准的cmd.exe和使用PowerShell的新型Windows终端上都会出现。在Mac和Linux上没有这样的问题,它可以很好地在终端关闭、ssh注销等情况下继续运行。
我尝试使用cmd.SysProcAttr来设置syscall.CREATE_NEW_PROCESS_GROUP,但没有任何效果。
我的问题是,为什么在Windows上关闭终端时会导致它终止,我该如何让它停止?
package main
import (
"fmt"
"os"
"os/exec"
"time"
)
var childEnv = "__IS_CHILD"
func main() {
if os.Getenv(childEnv) == "" {
fork()
os.Exit(0)
}
for i := 0; ; i++ {
fmt.Println(i)
time.Sleep(time.Second)
}
}
func fork() {
outfile, err := os.Create("output.txt")
if err != nil {
panic(err)
}
cmd := exec.Command(os.Args[0])
cmd.Env = append(os.Environ(), fmt.Sprintf("%v=%v", childEnv, 1))
cmd.Stdout = outfile
cmd.Stderr = outfile
if err = cmd.Start(); err != nil {
panic(err)
}
}
英文:
Consider this trivial Go program, which demonstrates the standard way to "fork off" a background process in Go. When it's run, it should immediately send itself to the background where it will write incrementing integers to output.txt once per second. It will keep running until you manually kill it.
This program works perfectly on Mac and Linux, but on Windows there is a weird behavior: it seems like it worked because I get a command prompt again immediately, and my process is indeed running in the background and writing those integers to output.txt. However, the background process gets killed when I close the terminal window.
The problem happens with both the standard cmd.exe, and the new fancy Windows Terminal that uses PowerShell. There is no such problem on Mac and Linux, where it quite properly survives terminal close, ssh logout, etc.
I tried using cmd.SysProcAttr to set syscall.CREATE_NEW_PROCESS_GROUP, but that made no difference.
My question is, what's causing it to die on Windows when the terminal is closed and how do I make it stop?
package main
import (
"fmt"
"os"
"os/exec"
"time"
)
var childEnv = "__IS_CHILD"
func main() {
if os.Getenv(childEnv) == "" {
fork()
os.Exit(0)
}
for i := 0; ; i++ {
fmt.Println(i)
time.Sleep(time.Second)
}
}
func fork() {
outfile, err := os.Create("output.txt")
if err != nil {
panic(err)
}
cmd := exec.Command(os.Args[0])
cmd.Env = append(os.Environ(), fmt.Sprintf("%v=%v", childEnv, 1))
cmd.Stdout = outfile
cmd.Stderr = outfile
if err = cmd.Start(); err != nil {
panic(err)
}
}
答案1
得分: 3
我明白了。我只需要添加下面的代码,那么当终端窗口关闭时,分离的进程就不会终止。
cmd.SysProcAttr = &syscall.SysProcAttr{
CreationFlags: windows.CREATE_NEW_PROCESS_GROUP | windows.DETACHED_PROCESS,
}
这里有关于Windows进程创建标志的文档:https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
英文:
I figured it out. I just need to add the code below, then the detached process won't die when the terminal window is closed.
cmd.SysProcAttr = &syscall.SysProcAttr{
CreationFlags: windows.CREATE_NEW_PROCESS_GROUP | windows.DETACHED_PROCESS,
}
There's documentation on Windows process creation flags here: https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论