第一种方式:
func fork1() (*os.Process, error) {
// 获取当前进程名和工作目录
execName, err := os.Executable() // 输出与 os.Args[0] 类似
if err != nil {
return nil, err
}
// 生成子进程
p, err := os.StartProcess(execName, []string{execName}, &os.ProcAttr{
Dir: filepath.Dir(execName), //工作路径 不包含文件名
Env: os.Environ(), // 获取当前环境变量 并且传入子进程
Files: []*os.File{
os.Stdin,
os.Stdout,
os.Stderr,
},
Sys: &syscall.SysProcAttr{},
})
if err != nil {
return nil, err
}
return p, nil
}
// 参考文章
// https://studygolang.com/articles/14038
第一种方式用法:
cmd, err := fork1()
if err != nil {
fmt.Println(err)
return
}
log.Printf("fork1 pid=%v name=%v\n", cmd.Pid, filepath.Base(args[0]))
os.Exit(0) // fork 进程后退出
第二种方式:
func fork2() (*exec.Cmd, error) {
path, err := os.Executable() // 与 os.Args[0] 类似
if err != nil {
return nil, err
}
cmd := &exec.Cmd{
Path: path, //文件路径 包括文件名
Args: []string{path}, //执行的命令
Dir: filepath.Dir(path), //文件路径 不包括文件名
Env: os.Environ(), //环境变量
Stdin: os.Stdin, // 输入
Stdout: os.Stdout, // 输出
Stderr: os.Stderr, // 错误
SysProcAttr: &syscall.SysProcAttr{},
/* SysProcAttr: &syscall.SysProcAttr{
Pdeathsig: syscall.SIGTERM,
},*/
}
err = cmd.Start() // 不阻塞地执行
if err != nil {
return nil, err
}
/* if err := cmd.Wait(); err != nil { // 阻塞
log.Panicf("failed to wait command: %s", err)
}*/
return cmd, nil
}
// 参考文章
// https://blog.csdn.net/u013755520/article/details/106262434
第二种方式用法:
cmd, err := fork2()
if err != nil {
fmt.Println("error: ", err)
return
}
fmt.Println("fork2 pid = ", cmd.Process.Pid) //获取pid
os.Exit(0) // fork 进程后退出
第三种方式:
windows下不可用
var args = os.Args
func fork3() (error, int) {
procAttr := &syscall.ProcAttr{
Env: os.Environ(),
Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
}
// windows下不可用
pid, err := syscall.ForkExec(args[0], []string{args[0]}, procAttr)
if err != nil {
return err, pid
}
return nil, pid
}
// 参考文章
// https://juejin.cn/post/6844903656891154446
第三种方式用法:
err, pid := fork3()
if err != nil {
fmt.Println("error", err)
return
}
log.Println("fork3 pid=", pid)
os,Exit(0) // fork 进程后退出