在Go中设置进程名称(由`ps`看到)

Rei*_*ica 8 linux process go

以下(正确地)不起作用:

package main

import (
        "os"
        "time"
)

func main() {
        os.Args[0] = "custom name"
        println("sleeping")
        time.Sleep(1000 * time.Second)
        println("done")
}
Run Code Online (Sandbox Code Playgroud)

有些语言提供了将进程名称设置为内置功能的特性(例如,在Ruby中,它只是分配给它 $0)或作为第三方库(Python).

我正在寻找一种至少适用于Linux的解决方案.

Kyl*_*ons 12

有多种方法可以实现这一点,其中许多方法仅适用于某些情况.我不建议这样做,因为(一方面)它可能导致你的进程在不同情况下显示不同的名称.它们需要使用系统调用和/或不安全,因此您故意破坏Go语言的安全性.尽管如此,您的选择似乎是:

修改argv [0]

func SetProcessName(name string) error {
    argv0str := (*reflect.StringHeader)(unsafe.Pointer(&os.Args[0]))
    argv0 := (*[1 << 30]byte)(unsafe.Pointer(argv0str.Data))[:argv0str.Len]

    n := copy(argv0, name)
    if n < len(argv0) {
            argv0[n] = 0
    }

    return nil
}
Run Code Online (Sandbox Code Playgroud)

在Go中,您无权访问实际的argv数组本身(不调用内部运行时函数),因此您只能使用不超过当前进程名称长度的新名称.

这似乎主要适用于Darwin和Linux.

致电PR_SET_NAME

func SetProcessName(name string) error {
    bytes := append([]byte(name), 0)
    ptr := unsafe.Pointer(&bytes[0])
    if _, _, errno := syscall.RawSyscall6(syscall.SYS_PRCTL, syscall.PR_SET_NAME, uintptr(ptr), 0, 0, 0, 0); errno != 0 {
            return syscall.Errno(errno)
    }
    return nil
}
Run Code Online (Sandbox Code Playgroud)

新名称最多为16个字节.

这在Darwin上不起作用,并且在Linux上似乎没什么用,尽管它成功了,PR_GET_NAME之后报告了正确的名称.不过,这可能是我的Linux VM特有的.

  • 顺便说一下, PR_SET_NAME 不起作用的原因是因为它将它设置在一个线程上,而不是主线程上。 (3认同)

zzz*_*zzz -1

我不认为“流程标题”是一个定义明确的术语。不管怎样,Ruby 和 Go 有什么关系呢?os.Args 的文档没有提到任何“进程标题”,也没有说分配给切片项时会发生任何魔法。后者实际上是 Go 的通用属性。结构体字段、数组/切片项的变量没有神奇的 getters/setters,所以简单的赋值只是简单地赋值,什么也不做,也不能做任何事情。

简而言之,缺乏魔法是预期的、正确的行为。

为了摆弄除通过“os”包可移植访问的进程属性之外的进程属性,必须以特定于平台的方式使用包“syscall”。但是构建约束(此处讨论)可以帮助正确处理跨平台的内容。

  • 我假设OP指的是[某些类Unix操作系统更改进程标题的能力](http://www.steve.org.uk/Reference/Unix/faq_toc.html#TOC22)。看起来这个属性并不通用。另一方面,我认为“os”包中用于此目的的函数会很有用。 (3认同)