【问题标题】:How to start a process?如何启动一个进程?
【发布时间】:2012-12-04 12:11:35
【问题描述】:

我尝试从如下所示的 Google Go 程序启动 JVM:

package main
import "fmt"
import "os"
import "log"
func main() {

var name string
name="\\jrex64\\bin\\java.exe"

var path="-Xbootclasspath:jrex64\\lib\\rt.jar;"+
"jrex64\\lib\\jfxrt.jar;"+
"jrex64\\lib\\resources.jar;"+
"jrex64\\lib\\ext\\sunjce_provider.jar;"+
"jrex64\\lib\\ext\\zipfs.jar;"+
"jrex64\\lib\\ext\\sunmscapi.jar;"+
"jrex64\\lib\\ext\\sunec.jar;"+
"jrex64\\lib\\ext\\dnsns.jar;"+
"jrex64\\lib\\ext\\access-bridge-64.jar;"+
"jrex64\\lib\\security\\local_policy.jar;"+
"jrex64\\lib\\jce.jar;"+
"jrex64\\lib\\jfr.jar;"+
"jrex64\\lib\\jsse.jar;"+
"jrex64\\lib\\charsets.jar;"+
"jrex64\\lib\\";



var args[] string=make([]string,4)
args[0]="-verbose"
args[1]=path;
args[2]="-cp Ganesha_lib\\*"
args[3]="-jar Ganesha.jar"

var attr* os.ProcAttr

proc,err:=os.StartProcess(name,args,attr)
proc.Wait();


if err!=nil {
    fmt.Println("an error occurred.\n")
    log.Fatal(err)
}

}

这是我的第一个围棋程序。我完全被以下错误弄得不知所措:

panic:运行时错误:无效的内存地址或 nil 指针取消引用 [信号0xc0000005代码=0x0地址=0x0 pc=0x4278b5] goroutine 1 [运行]: os.startProcess(0x4aacb4, 0x14, 0xf840001eb0, 0x500000005, 0x0, ...) C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist767862039/go/src/pkg/os/exec_posix.go:28 +0x152 os.StartProcess(0x4aacb4, 0x14, 0xf840001eb0, 0x500000005, 0x0, ...) C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist767862039/go/src/pkg/os/doc.go:24 +0x5c main.main() D:/MyGoProject/src/main.go:60 +0x23c goroutine 2 [系统调用]: 由 runtime.main 创建 C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist767862039/go/src/pkg/runtime/proc.c:221 进程以退出代码 2 结束

我该如何解释这个错误代码?什么地方出了错?以及如何获取 JVM startet - 它位于 Go 可执行文件的子目录中。

【问题讨论】:

  • 尝试在多行字符串中使用反引号 (`) 而不是双引号。您不需要用反引号来转义反斜杠。 See this example。此外,还有一个用于以独立于平台的方式连接路径的包,请参阅pkg/path/filepath。

标签: go


【解决方案1】:

这里:

var attr* os.ProcAttr

proc, err := os.StartProcess(name, args, attr)

attr 变量为 nil,当在 os.StartProcess 中取消引用时,它会导致您看到的错误。

【讨论】:

  • 那么我必须以某种方式实例化ProcAttr吗?
  • 我无法提供经过验证的源代码来做您想做的事情(这里没有 Java 也没有 Windows)。我建议使用os/exec 包包装器而不是os.StartProcess,它应该更易于使用。这是一个通用示例:golang.org/pkg/os/exec/#example_Cmd_Start(单击文本“示例”。)
【解决方案2】:

通常建议您不要直接使用 os.StartProcess。相反,使用 os/exec 具有更简单的界面。这是我将如何启动一个 java 子进程并等待它完成的方法。

http://play.golang.org/p/APlp9KK9wx

package main

import (
    "fmt"
    "log"
    "os/exec"
    "strings"
)

func main() {
    var java = "\\jrex64\\bin\\java.exe"

    var path = []string{
        "jrex64\\lib\\rt.jar",
        "jrex64\\lib\\jfxrt.jar",
        "jrex64\\lib\\resources.jar",
        "jrex64\\lib\\ext\\sunjce_provider.jar",
        "jrex64\\lib\\ext\\zipfs.jar",
        "jrex64\\lib\\ext\\sunmscapi.jar",
        "jrex64\\lib\\ext\\sunec.jar",
        "jrex64\\lib\\ext\\dnsns.jar",
        "jrex64\\lib\\ext\\access-bridge-64.jar",
        "jrex64\\lib\\security\\local_policy.jar",
        "jrex64\\lib\\jce.jar",
        "jrex64\\lib\\jfr.jar",
        "jrex64\\lib\\jsse.jar",
        "jrex64\\lib\\charsets.jar",
        "jrex64\\lib\\",
    }

    pathflag := "-Xbootclasspath:" + strings.Join(path, ";")
    cmd := exec.Command(java, "-verbose", pathflag, "-cp Ganesha_lib\\*", "-jar Ganesha.jar")
    err := cmd.Run()

    if err != nil {
        fmt.Println("an error occurred.\n")
        log.Fatal(err)
    }

}

如果你很好奇,你得到恐慌的原因是 attr 是一个 nil 指针。相反,您可以使用attr := new(os.ProcAttr)。

【讨论】:

  • 您需要所有这些 \\ 标记吗?因为 Windows 支持 Posix,我认为你可以使用 / 来代替,它更易于阅读并且可以移植到其他 Posix 文件系统(特别是 Linux、Macos)
【解决方案3】:

前面的答案实际上并没有描述如何使用 os.StartProcess()。这是一个例子:

cmdToRun := "/path/to/someCommand"
args := []string{"someCommand", "arg1"}
procAttr := new(os.ProcAttr)
procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}
if process, err := os.StartProcess(cmdToRun, args, procAttr); err != nil {
    fmt.Printf("ERROR Unable to run %s: %s\n", cmdToRun, err.Error())
} else {
    fmt.Printf("%s running as pid %d\n", cmdToRun, process.Pid)
}

请注意,有必要初始化 ProcAttr.Files 字段 - 如果不这样做,您可能会在 os 包深处得到索引越界错误。如果您想在自己的代码中提供来自新进程的输入或进程输出,则可以对文件使用管道。您可能还想指定 Dir(起始目录)和 Env(环境变量)字段。

【讨论】:

  • 原因是直接使用 os.StartProcess 从来都不是你想做的事情。他没有问如何使用 StartProcess,而是问如何启动一个进程。我回答了他失败的原因,并向他指出了一种更好的实施方式。我不确定他为什么将您的答案标记为正确。
  • @steve 您可能应该与 Go 的作者讨论这个问题。如果直接使用 os.StartProcess 是您永远不想做的事情,那么他们在暴露该方法时犯了一个错误。事实上,我在网上找不到任何支持您声明不应使用 startProcess 的说法。你能指点参考吗?
  • 来自文档:“StartProcess 是一个低级接口。os/exec 包提供了更高级别的接口。”通常这意味着如果您正在做一些高级的事情,使用 StartProcess 是有意义的。但是,你可以用启动过程做的所有事情都可以用 os/exec 来完成(个人研究,易于验证)。 StartProcess 在那里是因为它被 os/exec 使用并且它适合 kill and wait 在那里。这些是因为你可能想要等待/终止一个你没有启动的进程。
  • 文档说这是一个低级接口。它并没有说不要使用它。 IMO,仅仅因为问题的作者比你更喜欢它而降级答案是很不酷的。只是说。
  • 嗯,不应该投反对票,但肯定会让人们远离使用 StartProcess。你是对的。不幸的是,无法撤消反对票。另外,回顾这个​​问题,我需要检查它是否仍然相关。我可能应该提交一个补丁以允许 attr 为 nil。
【解决方案4】:

在 Windows 上,os.ProcAttr 不能为空。 At Dir 必须设置为空字符串,Sys 必须设置为 &syscall.SysProcAttr{}。以下应该有效:

name := "\\jrex64\\bin\\java.exe"
libs := "-Xbootclasspath:jrex64\\lib\\rt.jar;" +
    // add all libs
    "jrex64\\lib\\";
args := []string{"-verbose", libs, "-cp Ganesha_lib\\*", "-jar Ganesha.jar"}
attr := &os.ProcAttr{
    "",
    nil,
    []*os.File{os.Stdin, os.Stdout, os.Stderr},
    &syscall.SysProcAttr{}} //CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP, } 
}

proc, err := os.StartProcess(name,args,attr);
if err != nil {
    log.Fatalf("start process: %v", err)
}
_, err = proc.Wait();
if err != nil {
    log.Fatalf("wait: %v", err)
}

【讨论】:

    猜你喜欢
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多