我正在try 使用我的守护进程派生进程,并试图在我的守护进程崩溃的情况下否认它们.常规os/exec是高级的,因此我 Select 了syscall.ForkExec,并生成了以下代码:

package main

import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
    "time"
)

func main() {

    cmd := "myproc"
    binary, lookErr := exec.LookPath(cmd)
    if lookErr != nil {
        panic(lookErr)
    }
    fmt.Println(binary)

    os.Remove("/tmp/stdin")
    os.Remove("/tmp/stdout")
    os.Remove("/tmp/stderr")

    fstdin, err1 := os.Create("/tmp/stdin")
    fstdout, err2 := os.Create("/tmp/stdout")
    fstderr, err3 := os.Create("/tmp/stderr")
    if err1 != nil || err2 != nil || err3 != nil {
        fmt.Println(err1, err2, err3)
        panic("WOW")
    }

    argv := []string{"hi"}
    procAttr := syscall.ProcAttr{
        Dir:   "/tmp",
        Files: []uintptr{fstdin.Fd(), fstdout.Fd(), fstderr.Fd()},
        Env:   []string{"VAR1=ABC123"},
        Sys: &syscall.SysProcAttr{
            Foreground: false,
        },
    }

    pid, err := syscall.ForkExec(binary, argv, &procAttr)
    fmt.Println("Spawned proc", pid, err)

    time.Sleep(time.Second * 100)
}

我还制作了一个简单的应用程序,用于Hibernate 和打印hello world,并将其放到path中.

#include <stdio.h>

int main(){
    while(1){
        printf("hello world");
        fflush(stdout);
        usleep(300000);
        }
}

它可以工作,但是,进程并没有像我预期的那样发送到后台,我的围棋进程仍然拥有子进程.SysProcAttr在Linux中具有以下值:

type SysProcAttr struct {
    Chroot      string         // Chroot.
    Credential  *Credential    // Credential.
    Ptrace      bool           // Enable tracing.
    Setsid      bool           // Create session.
    Setpgid     bool           // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
    Setctty     bool           // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
    Noctty      bool           // Detach fd 0 from controlling terminal
    Ctty        int            // Controlling TTY fd
    Foreground  bool           // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
    Pgid        int            // Child's process group ID if Setpgid.
    Pdeathsig   Signal         // Signal that the process will get when its parent dies (Linux only)
    Cloneflags  uintptr        // Flags for clone calls (Linux only)
    UidMappings []SysProcIDMap // User ID mappings for user namespaces.
    GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
    // GidMappingsEnableSetgroups enabling setgroups syscall.
    // If false, then setgroups syscall will be disabled for the child process.
    // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged
    // users this should be set to false for mappings work.
    GidMappingsEnableSetgroups bool
}

我还try 了以下操作,但导致错误:

Sys: &syscall.SysProcAttr{
    Setsid:     true,
    Setctty:    true,
    Foreground: false,
 },

Spawned proc 0 inappropriate ioctl for device

还包括以下内容:

Sys: &syscall.SysProcAttr{
    Setsid:     true,
    Setctty:    true,
    Foreground: false,
    Noctty:     true,
    Setpgid:    true,
},

Spawned proc 0 operation not permitted (with root privilleges)

我做错了什么/假设错了什么? Note:尽管我说os/exec是高级的,但我也try 了以下方法,但都产生了相同的结果.

cs := exec.Command(binary)
cs.SysProcAttr = &syscall.SysProcAttr{
    Setctty: true,
}
err := cs.Run()
fmt.Println(err)

推荐答案

一个Forking 为Start()的进程即使在其父进程死亡后仍将继续.

func forker() {
    cmd := exec.Command("sleep", "3")
    cmd.Start()
    time.Sleep(2 * time.Second)
    os.Exit(1)
}

在这里,sleep进程将愉快地持续3秒,即使父进程只持续2秒:

  $ forker &; while true; do ps -f; sleep 1; done

  UID   PID  PPID   C STIME   TTY           TIME CMD
  501 71423 69892   0  3:01PM ttys003    0:00.07 forker
  501 71433 71432   0  3:01PM ttys003    0:00.00 sleep 3

  UID   PID  PPID   C STIME   TTY           TIME CMD
  501 71423 69892   0  3:01PM ttys003    0:00.07 forker
  501 71433 71432   0  3:01PM ttys003    0:00.00 sleep 3

  UID   PID  PPID   C STIME   TTY           TIME CMD
  501 71433     1   0  3:01PM ttys003    0:00.00 sleep 3

请注意,当父进程71432退出时,sleep进程的父进程ID(PPID)如何变为1.这意味着sleep进程已成为孤立进程.

Go相关问答推荐

VS代码,Golang格式顽固的情况与switch / case

Golang文本/模板序列范围

Golang中的泛型 struct /接口列表

Wamtime Memory中的‘Offset’是什么?Read?

go grpc:无法导入github.com/golang/protobuf/proto(没有所需的模块提供包github.com/gorang/protobuf-proto)

如何使用 AWS sdk 在 Go 中正确解组 PartiQL 查询的结果?

testcontainers:如何修复绑定源路径不存在

从 ApiGateway 中的 lambda Go 返回 Json

这是实现超时的常见方法,为什么 time.After 不起作用

如何将 DirName 和 serial 添加到 X509v3 Authority Key Identifier

在本地 go 应用程序上获取秘密的正确策略

MQTT 客户端没有收到另一个客户端发送的消息

当图像是对象数组的元素时,如何显示存储为页面资源的图像?

从Go中的随机日期开始以天为单位获取时间

获取切片元素的地址是否意味着 Go 中元素的副本?

Go gmail api 快速入门导致本地主机拒绝连接 ERR_CONNECTION_REFUSED

在 Go 中发送 ack 和 term 后消息仍在 nats 限制队列中

Golang BigInt 部门

将 Golang Gin 与 AWS Lambda 和无服务器与代理路径一起使用

防止在 Go 公用文件夹中列出目录