os.FindProcess în Go

Returnează un *os.Process pentru PID-ul dat, ca să-i poți trimite semnale, să-l oprești sau să-l aștepți.

Sintaxă
func FindProcess(pid int) (*Process, error)

Ce face os.FindProcess

os.FindProcess creează o valoare *os.Process pentru procesul cu numărul pid. Cu ea poți trimite semnale (p.Signal(os.Interrupt), p.Signal(syscall.SIGTERM)), poți opri procesul (p.Kill()) sau, dacă este procesul tău copil, îl poți aștepta (p.Wait()).

Pe Linux și macOS funcția reușește întotdeauna, chiar dacă procesul nu există; afli asta abia când trimiți un semnal. Un truc des folosit: p.Signal(syscall.Signal(0)) nu face nimic procesului, dar dă eroare dacă procesul nu există sau nu ai voie să-i trimiți semnale. Pe Windows, FindProcess dă eroare dacă procesul nu există.

Parametri

Parametru Descriere
pid ID-ul procesului (de exemplu citit dintr-un fișier .pid).

Ce returnează

Un *os.Process și nil (pe Unix mereu), sau o eroare.

Exemple

Exemplul 1: Semnal trimis propriului proces

package main

import (
    "fmt"
    "os"
    "os/signal"
)

func main() {
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)

    p, err := os.FindProcess(os.Getpid())
    fmt.Println("găsit:", p.Pid == os.Getpid(), err)

    p.Signal(os.Interrupt)
    fmt.Println("primit:", <-c)
}

Rezultat

găsit: true <nil>
primit: interrupt

Exemplul 2: Mai rulează procesul?

Pornim un proces copil, îl verificăm cu semnalul 0, îl oprim și verificăm din nou.

package main

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

func ruleaza(pid int) bool {
    p, err := os.FindProcess(pid)
    if err != nil {
        return false
    }
    return p.Signal(syscall.Signal(0)) == nil
}

func main() {
    cmd := exec.Command("sleep", "30")
    cmd.Start()
    pid := cmd.Process.Pid
    fmt.Println("rulează:", ruleaza(pid))

    p, _ := os.FindProcess(pid)
    p.Kill()
    cmd.Wait()
    fmt.Println("după Kill rulează:", ruleaza(pid))
}

Rezultat

rulează: true
după Kill rulează: false

Exemplul 3: Oprirea unui server după fișierul .pid

package main

import (
    "fmt"
    "os"
    "strconv"
    "strings"
    "syscall"
)

func main() {
    date, err := os.ReadFile("/var/run/magazin.pid")
    if err != nil {
        fmt.Println("serverul nu pare pornit:", err)
        return
    }
    pid, _ := strconv.Atoi(strings.TrimSpace(string(date)))
    p, _ := os.FindProcess(pid)
    if err := p.Signal(syscall.SIGTERM); err != nil {
        fmt.Println("nu pot opri procesul", pid, ":", err)
        return
    }
    fmt.Println("am cerut oprirea procesului", pid)
}

Rezultat posibil (diferă la fiecare rulare)

am cerut oprirea procesului 48213

Greșeli frecvente

  • Verifici existența procesului doar prin eroarea lui FindProcess. Pe Unix funcția reușește mereu; trimite semnalul 0.
  • Trimiți semnale către PID-uri vechi din fișiere .pid uitate. Numărul poate aparține acum altui proces.

Comenzi înrudite

  • os.Getpid: Getpid returnează ID-ul procesului curent; Getppid, ID-ul procesului care l-a pornit (părintele).
  • signal.Notify: Trimite semnalele primite de program (Ctrl+C, SIGTERM) pe un canal, ca să le tratezi; Stop oprește trimiterea.
  • os.StartProcess: Pornește un proces nou la nivel scăzut, cu programul, argumentele și fișierele date; de obicei folosești os/exec.
  • exec.Cmd.Start: Start pornește comanda fără să aștepte; Wait așteaptă terminarea ei și eliberează resursele.