6

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

mklement0
  • 382,024
  • 64
  • 607
  • 775
Sergey
  • 99
  • 6
  • What happens to your standard output when the terminal closes? In linux it will be redirected to null output, but not in windows. – jdweng Dec 19 '22 at 18:40
  • The main process is creating a child process whose stdout/stderr is redirected to a file. The main process is then exiting immediately. Only the child process continues to run, detached from the terminal. – Sergey Dec 19 '22 at 18:44
  • Does file get created? – jdweng Dec 19 '22 at 19:35

1 Answers1

3

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

Sergey
  • 99
  • 6