Home  >  Article  >  Backend Development  >  How to gracefully shut down child processes in Golang

How to gracefully shut down child processes in Golang

PHPz
PHPzOriginal
2023-04-25 09:19:261076browse

Golang is a powerful programming language that supports multi-process programming. Starting a child process in Go is easy, but closing it requires some tricks. This article will introduce how to gracefully shut down child processes in Golang.

1. Starting a subprocess
Starting a subprocess in Golang is very simple. You can use the Command function in the exec package. The following is an example of starting a command:

cmd := exec.Command("ls", "-l")
err := cmd.Start()
if err != nil {
    log.Fatal(err)
}

This code will start a child process of the "ls -l" command.

2. Close the child process
When the child process is completed, we need to call the Wait function to wait for the child process to close. However, if we are starting the child process in an infinite loop, then some more advanced tricks are needed to shut down the child process.

First, we need to store the PID of the child process in a variable. This can be achieved using the Getpid function in the syscall package. Then, when we need to shut down the child process, we can use the Kill function in the syscall package to send an operating system signal.

package main
 
import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
    "time"
)
 
func main() {
    cmd := exec.Command("sleep", "10")
    err := cmd.Start()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
 
    pid := cmd.Process.Pid
 
    fmt.Printf("Child process started: %v\n", pid)
 
    time.AfterFunc(time.Second*5, func() {
        err := syscall.Kill(pid, syscall.SIGTERM)
        if err != nil {
            fmt.Println(err)
        } else {
            fmt.Printf("Child process %v terminated\n", pid)
        }
    })
 
    cmd.Wait()
 
    fmt.Println("Parent process exiting.")
}

This program will start a child process with the "sleep 10" command, then wait 5 seconds and then send the SIGTERM signal to kill the child process. We use the time.AfterFunc function to perform the operation after 5 seconds and the syscall.Kill function to send the signal. After completing the operation, we use the cmd.Wait function to wait for the child process to close.

3. Gracefully shut down the child process
In the above example, we sent a SIGTERM signal to shut down the child process. This signal will be caught by the process, and the process can do some cleanup work after catching the signal, and then exit normally.

If the child process does not catch the signal, we need to use the SIGKILL signal to force the child process to close. This signal will kill the process directly without giving the process any chance to clean up. Forcibly closing a child process may cause the process to leave temporary files and occupy system resources.

Gracefully shutting down a child process can be achieved by sending an exit signal to the child process. This signal can be caught by a child process and the process safely shut down after catching.

To use the exit signal, we need to support the signal in the code of the child process. In Golang, this can be achieved through the Signal function in the os package. Here is an example of a subprocess that supports exit signals:

package main
 
import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time"
)
 
func main() {
    fmt.Println("Child process started.")
 
    sigchan := make(chan os.Signal, 1)
    signal.Notify(sigchan, syscall.SIGTERM)
 
    go func() {
        <-sigchan
        fmt.Println("Received SIGTERM signal, exiting...")
        os.Exit(0)
    }()
 
    // Start doing some meaningful work.
    for {
        fmt.Println("Working...")
        time.Sleep(time.Second)
    }
}

This program starts an infinite loop and prints "Working..." every second. In the code of the child process, we create a signal channel sigchan and use the signal.Notify function to send the SIGTERM signal to the channel.

We then wait in an infinite loop to receive the signal. Once this signal is received, we print an exit message and terminate the process using the os.Exit function.

Now, we already have a subprocess that supports exit signals. We can use the following code to close it:

package main
 
import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
    "time"
)
 
func main() {
    cmd := exec.Command("./child")
    err := cmd.Start()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
 
    pid := cmd.Process.Pid
 
    fmt.Printf("Child process started: %v\n", pid)
 
    time.AfterFunc(time.Second*5, func() {
        err := syscall.Kill(pid, syscall.SIGTERM)
        if err != nil {
            fmt.Println(err)
        } else {
            fmt.Printf("Child process %v terminated\n", pid)
        }
    })
 
    cmd.Wait()
 
    fmt.Println("Parent process exiting.")
}

This program will start a subprocess of the test1 command and wait for 5 seconds. Then send the SIGTERM signal to close the child process. Under normal circumstances, the child process should print an exit message and exit normally.

To sum up, closing the child process is not very difficult in Golang. We can use the Kill function in the syscall package to send signals, or support exit signals in the code of the child process to gracefully shut down the child process.

The above is the detailed content of How to gracefully shut down child processes in Golang. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn