2013-03-04 9 views
12

Jeśli mam PID procesu, czy jest os.FindProcess wystarczy, aby przetestować istniejący proces? Chodzi mi o to, że jeśli wróci err, czy mogę założyć, że zostało zakończone (lub zabite)?Sprawdź, czy proces istnieje w ruchu

Edit:

Właśnie napisałem funkcję otoki wokół kill -s 0 (proces testowania bash w starym stylu). To działa bez problemu, ale nadal jestem zadowolony, jeśli nie ma innych rozwiązań (wykonane z Go bibliotek) do tego problemu .:

func checkPid(pid int) bool { 
    out, err := exec.Command("kill", "-s", "0", strconv.Itoa(pid)).CombinedOutput() 
    if err != nil { 
     log.Println(err) 
    } 

    if string(out) == "" { 
     return true // pid exist 
    } 
    return false 
} 

Odpowiedz

26

Oto tradycyjny UNIX sposób, aby zobaczyć, czy proces jest żywy - wyślij go do nas sygnał 0 (tak jak w przypadku twojego basha).

Od kill(2):

If sig is 0, then no signal is sent, but error checking is still per‐ 
    formed; this can be used to check for the existence of a process ID or 
    process group ID. 

A języku idź

package main 

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

func main() { 
    for _, p := range os.Args[1:] { 
     pid, err := strconv.ParseInt(p, 10, 64) 
     if err != nil { 
      log.Fatal(err) 
     } 
     process, err := os.FindProcess(int(pid)) 
     if err != nil { 
      fmt.Printf("Failed to find process: %s\n", err) 
     } else { 
      err := process.Signal(syscall.Signal(0)) 
      fmt.Printf("process.Signal on pid %d returned: %v\n", pid, err) 
     } 

    } 
} 

Po uruchomieniu go można dostać to, pokazując, że proces 123 nie żyje, proces 1 jest żywy, ale nie posiadane przez ciebie i proces 12606 jest żywy i posiadany przez ciebie.

$ ./kill 1 $$ 123 
process.Signal on pid 1 returned: operation not permitted 
process.Signal on pid 12606 returned: <nil> 
process.Signal on pid 123 returned: no such process 
+0

To wszystko! Dzięki za pokazanie drogi :) –

+0

Dlaczego parsujesz w 'int64'. Czy "Atoi" nie byłoby lepsze (bez konwersji typu w 'FindProcess')? – tjameson

+0

Tak, masz rację "Atoi" byłoby lepiej. Chyba ostatnio użyłem 'ParseInt' i zapomniałem o tym! –

5

w systemie UNIX, takich jak systemy (Linux, FreeBSD, etc) os.FindProcess będzie nigdy nie zwróci błędu. Nie wiem, co dzieje się w systemie Windows. Oznacza to, że nie będziesz wiedział, czy PID jest poprawny, dopóki nie spróbujesz użyć czegoś * os.Process.

Możesz spojrzeć na kod here.

+0

Masz rację.To zawsze daje prawdziwe, znalazłem obejście (zobacz moją edycję powyżej) –

+0

Z mojego doświadczenia na Windows 10, 'os.FindProcess' zwraca błąd, jeśli proces z danym PID nie jest uruchomiony. – Kerrmiter

1

Jeśli poprzednio znany pid nie został znaleziony w systemie (brak pewności co do funkcji go), oznacza to, że proces został definitywnie zakończony i został dołączony (na Unix, z wait call).

Ale w inny sposób niekoniecznie musi to być prawda. Tylko dlatego, że istnieje pid, nie gwarantuje, że jest to ten sam proces, co poprzednio. Na przykład w standardowym systemie Linux istnieje tylko 65535 poprawnych identyfikatorów i można je ponownie wykorzystać, gdy jest zawijany. Jeśli jednak sprawdzisz często, z praktycznego punktu widzenia nie musisz się tym przejmować (o ile pid z błędnego nowego procesu nie jest luką w zabezpieczeniach lub czymś innym krytycznym, którą ktoś może próbować wywołać celowo dla złośliwego cele).

Powiązane linki (i inne pytania na temat ich prawych kolumnach):

+0

Chciałbym móc głosować więcej niż jeden raz. Obserwacja, że ​​pidy są ponownie wykorzystywane, jest krytyczna dla każdego, kto chce niezawodnie monitorować procesy na nowoczesnym sprzęcie: jeśli coś źle się dzieje i odradza się, przestrzeń nazw pidów zostanie szybko wyczerpana. Ponieważ id wątków są w tej samej przestrzeni nazw co identyfikatory procesów, silnie powiązane procesy zaostrzają problem. – Mark

+1

Zapomniałem wspomnieć ... Jeśli potrzebujesz dodatkowej pewności, sprawdź, czy [czas rozpoczęcia procesu] (http://unix.stackexchange.com/a/7871/158521) dla $ pid nie zmienił się między kontrolami. Jeśli tak, to jest to inny proces. Jeśli nie, to jest bardzo mało prawdopodobne, aby był to inny proces. – Mark

+0

Co masz na myśli przez "wysoce nieprawdopodobne"? W jakich okolicznościach może to * nie * być innym procesem? Zakładając, że proces był żywy dłużej niż jedna jednostka, niezależnie od czasu rozpoczęcia, mierzona jest w (więc szybka kostka/odtworzyć z oblewaniem PID nie pomyliła kontrolera), jedyną okolicznością, którą mogę wymyślić, jest zawijanie w czasie początkowym. Czy są inni? –

2

Można również po prostu użyć syscall.Kill. To mniej kodu.

killErr := syscall.Kill(pid, syscall.Signal(0)) 
procExists := killErr == nil 
+0

Z wyjątkiem wiadomości od [Nick Craig-Wood's answer] (http://stackoverflow.com/a/15210305/55504), że nie zerowy błąd może zostać zwrócony dla istniejących procesów. Powinieneś mieć bardziej zaangażowany tryb warunkowy (być może "err == zero"; err == syscall.EPERM ", być może więcej). –

0

W systemie Windows sprawdzenie wyniku os.FindProcess() wydaje się wystarczające do sprawdzenia, czy proces jest uruchomiony.

func isProcessRunning(pid int) bool { 
    _, err = os.FindProcess(pid) 
    if err != nil { 
     return false 
    } 
    if runtime.GOOS == "windows" { 
     return true 
    } 
    return false // further checking for other systems then Windows is not supported here 
}