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

huangapple go评论95阅读模式
英文:

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

huangapple
  • 本文由 发表于 2022年12月20日 02:34:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/74854616.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定