这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天 Go 语言中创建进程的方法。 Unix 中创建进程,其主要使用系统调用fork,execve,wait和exit。 在Go语言中,Linux 下创建进程使用的系统调用是clone,使用syscall.ForkExec将fork和execve合二为一提供了一种创建进程的方法。
os.Process 存储了通过 StartProcess 创建的进程的相关信息,而StartProcess使用提供的程序名、命令行参数、属性开始一个新进程。如果出错,错误的类型会是*PathError。ProcAttr 用于为 StartProcess 创建新进程提供一些属性,可以指定进程的目录、环境变量和继承的打开文件对象等。FindProcess 可以通过pid查找一个运行中的进程。
在使用创建进程的API时,一般应该优先使用os/exec包,因为它依赖于os包中关键的创建进程的API。os/exec包提供了高级别的接口,其中最重要的是Command函数。Command函数使用提供的命令和参数开始一个新进程,这样就不需要直接使用StartProcess函数,而是更加方便地为命令和参数提供了更高级别的接口。另一个重要的函数是LookPath,它查找一个可执行文件,返回完整路径或错误。使用这个函数可以避免写死文件路径,使程序在不同操作系统上更具有可移植性。
在Windows上创建进程,使用CreateProcess函数,但是无法直接使用syscall包,而是需要导入syscall/windows包。在Windows上,使用os/exec包中的函数与在Unix上略有不同,但使用方式类似。需要在Windows上创建进程时,使用Command函数和LookPath函数的方式与在Unix上相同。
package main
import (
"fmt"
"os/exec"
"time"
)
func main() {
cmd := exec.Command("notepad.exe")
if err := cmd.Start(); err != nil {
fmt.Printf("Failed to start notepad.exe: %v\n", err)
return
}
fmt.Println("notepad.exe started, pid:", cmd.Process.Pid)
time.Sleep(10 * time.Second)
if err := cmd.Process.Kill(); err != nil {
fmt.Printf("Failed to stop notepad.exe: %v\n", err)
return
}
fmt.Println("notepad.exe stopped")
}
Windows 平台下的 Kill 方法有一些限制,它只能终止当前进程及其子进程,而不能终止其他进程。如果需要终止其他进程,可以使用一些第三方库,比如 github.com/AllenDang/w32。