Wie man auf das Beenden von Nicht-Kind-Prozessen wartet

Lesezeit: 6 Minuten

Benutzeravatar von CsTamas
CsTamas

Für untergeordnete Prozesse ist die wait() und waitpid() Funktionen können verwendet werden, um die Ausführung des aktuellen Prozesses auszusetzen, bis ein untergeordneter Prozess beendet wurde. Diese Funktion kann jedoch nicht für nicht untergeordnete Prozesse verwendet werden.

Gibt es eine andere Funktion, die auf das Beenden eines Prozesses warten kann?

Benutzeravatar von chaos
Chaos

Nichts gleichbedeutend mit wait(). Die übliche Praxis ist die Abfrage mit kill(pid, 0) und Suche nach Rückgabewert -1 und errno von ESRCH um anzuzeigen, dass der Prozess beendet ist.

Aktualisieren: Seit Linux Kernel 5.3 gibt es eine pidfd_open syscall, der ein fd für eine bestimmte PID erstellt, das abgefragt werden kann, um eine Benachrichtigung zu erhalten, wenn PID beendet wurde.

  • Ist es in Ordnung, eine solche Besetztschleife zu haben?

    – CsTamas

    21. Juli 2009 um 7:37 Uhr

  • Nun, Sie wollen es nicht zu beschäftigt machen; Du solltest usleep() für eine Weile nach jedem kill() das findet den Prozess nicht gegangen. Dann müssen Sie ein Gleichgewicht zwischen der Auslastung Ihrer Umfragen und der Zeit finden, in der der Vorgang abgeschlossen sein kann, bevor Sie es bemerken.

    – Chaos

    21. Juli 2009 um 7:41 Uhr

  • Oh, usleep() wurde anscheinend obsolet, während ich nicht hinsah. Anscheinend sollten Sie das jetzt tun nanosleep() stattdessen.

    – Chaos

    21. Juli 2009 um 7:43 Uhr

  • @Sam Hocevar: Und nichts darüber, woraus die Rennbedingung besteht oder wie man dies ohne sie macht. Hilft nicht wirklich.

    – Chaos

    10. Januar 2012 um 15:34 Uhr

  • @chaos: Nichts garantiert das kill(pid, 0) signalisiert den Prozess, an dem Sie interessiert sind. Er könnte während Ihres Aufrufs abgebrochen und durch einen anderen laufenden Prozess ersetzt worden sein nanosleep. Ich fürchte, ich brauche nicht weiter darauf einzugehen: Es wurden drei gute Vorschläge gemacht (der FIFO, die Semaphore und die ptrace Ansatz, der meiner Meinung nach allen anderen überlegen ist, obwohl er sehr plattformspezifisch ist).

    – sam hocevar

    10. Januar 2012 um 16:14 Uhr

Auf BSDs und OS X können Sie kqueue mit EVFILT_PROC+NOTE_EXIT verwenden, um genau das zu tun. Keine Abfrage erforderlich. Leider gibt es kein Linux-Äquivalent.

  • Schade um Linux, dass sie kqueue nicht portiert haben.

    – Lothar

    9. Januar 2013 um 0:43 Uhr

Benutzeravatar von David Z
David z

Bisher habe ich drei Möglichkeiten gefunden, dies unter Linux zu tun:

  • Polling: Sie überprüfen von Zeit zu Zeit, ob der Prozess existiert, entweder durch Verwendung von kill oder durch Testen auf das Vorhandensein von /proc/$pidwie in den meisten anderen Antworten
  • Verwenden Sie die ptrace Systemaufruf zum Anhängen an den Prozess wie ein Debugger, damit Sie benachrichtigt werden, wenn er beendet wird, wie in der Antwort von a3nm
  • Verwenden Sie die netlink Schnittstelle zu hören PROC_EVENT_EXIT Nachrichten – auf diese Weise teilt der Kernel Ihrem Programm jedes Mal mit, wenn ein Prozess beendet wird, und Sie warten nur auf die richtige Prozess-ID. Ich habe das nur beschrieben gesehen an einem Ort im Internet.

Schamloser Stecker: Ich arbeite an einem Programm (Open Source natürlich; GPLv2), das alle drei tut.

Benutzeravatar von Aaron Digulla
Aaron Digulla

Sie könnten auch einen Socket oder einen FIFO erstellen und darauf lesen. Der FIFO ist besonders einfach: Verbinden Sie den Standardausgang Ihres Kindes mit dem FIFO und lesen Sie ihn aus. Der Lesevorgang wird blockiert, bis das untergeordnete Element (aus irgendeinem Grund) beendet wird oder bis es einige Daten ausgibt. Sie benötigen also eine kleine Schleife, um die unerwünschten Textdaten zu verwerfen.

Wenn Sie Zugriff auf die Quelle des Kindes haben, öffnen Sie das FIFO zum Schreiben, wenn es beginnt, und vergessen Sie es dann einfach. Das Betriebssystem bereinigt den geöffneten Dateideskriptor, wenn das Kind beendet wird, und Ihr wartender “Eltern”-Prozess wird aufwachen.

Nun, dies könnte ein Prozess sein, den Sie nicht gestartet haben oder dessen Eigentümer Sie nicht sind. In diesem Fall können Sie die ausführbare Binärdatei durch ein Skript ersetzen, das die eigentliche Binärdatei startet, aber auch die oben beschriebene Überwachung hinzufügt.

Benutzeravatar von l_belev
l_belev

Hier ist eine Möglichkeit, darauf zu warten, dass ein Prozess (nicht unbedingt ein Kind) in Linux ohne Abfrage beendet wird (oder getötet wird):

Die Verwendung von inotify zum Warten auf das Löschen von /proc’pid’ wäre die perfekte Lösung, aber leider funktioniert inotify nicht mit Pseudo-Dateisystemen wie /proc. Wir können es jedoch mit der ausführbaren Datei des Prozesses verwenden. Solange der Prozess noch existiert, wird diese Datei offen gehalten. Wir können also inotify mit IN_CLOSE_NOWRITE verwenden, um zu blockieren, bis die Datei geschlossen wird. Natürlich kann es aus anderen Gründen geschlossen werden (z. B. wenn ein anderer Prozess mit derselben ausführbaren Datei beendet wird), also müssen wir diese Ereignisse auf andere Weise filtern.

Wir können kill(pid, 0) verwenden, aber das kann nicht garantieren, dass es immer noch derselbe Prozess ist. Wenn wir diesbezüglich wirklich paranoid sind, können wir etwas anderes tun.

Hier ist ein Weg, der 100% sicher gegen Probleme bei der Wiederverwendung von PID sein sollte: Wir öffnen das Pseudo-Verzeichnis /proc/’pid’ und lassen es offen, bis wir fertig sind. Wenn in der Zwischenzeit ein neuer Prozess mit derselben PID erstellt wird, verweist der Verzeichnisdateideskriptor, den wir halten, immer noch auf den ursprünglichen (oder wird ungültig, wenn der alte Prozess nicht mehr existiert), bezieht sich aber NIEMALS auf den neuen Prozess die wiederverwendete pid. Dann können wir prüfen, ob der ursprüngliche Prozess noch existiert, indem wir zum Beispiel mit openat() prüfen, ob die Datei „cmdline“ im Verzeichnis existiert. Wenn ein Prozess beendet oder beendet wird, existieren auch diese Pseudodateien nicht mehr, sodass openat() fehlschlägt.

hier ist ein beispielcode:

// return -1 on error, or 0 if everything went well
int wait_for_pid(int pid)
{
    char path[32];
    int in_fd = inotify_init();
    sprintf(path, "/proc/%i/exe", pid);
    if (inotify_add_watch(in_fd, path, IN_CLOSE_NOWRITE) < 0) {
        close(in_fd);
        return -1;
    }
    sprintf(path, "/proc/%i", pid);
    int dir_fd = open(path, 0);
    if (dir_fd < 0) {
        close(in_fd);
        return -1;
    }

    int res = 0;
    while (1) {
        struct inotify_event event;
        if (read(in_fd, &event, sizeof(event)) < 0) {
            res = -1;
            break;
        }
        int f = openat(dir_fd, "fd", 0);
        if (f < 0) break;
        close(f);
    }

    close(dir_fd);
    close(in_fd);
    return res;
}

Du könntest den Vorgang mit anhängen ptrace(2). Aus der Schale, strace -p PID >/dev/null 2>&1 scheint zu funktionieren. Dies vermeidet das geschäftige Warten, obwohl es den verfolgten Prozess verlangsamt und nicht bei allen Prozessen funktioniert (nur bei Ihrem, was etwas besser ist als nur bei untergeordneten Prozessen).

Benutzeravatar von Jochen Walter
Jochen Walter

Mir sind keine bekannt. Abgesehen von der Lösung des Chaos können Sie Semaphoren verwenden, wenn Sie das Programm ändern können, auf das Sie warten möchten.

Die Bibliotheksfunktionen sind sem_open(3), sem_init(3), sem_wait(3),

sem_wait(3) führt eine Wartezeit durch, so dass Sie nicht wie bei der Chaos-Lösung geschäftig warten müssen. Natürlich macht die Verwendung von Semaphoren Ihre Programme komplexer und es lohnt sich vielleicht nicht.

  • Diese Semaphoren sind praktisch nutzlos, da sie bestehen bleiben, auch wenn kein Prozess sie geöffnet hat. Ich erinnere mich, dass ich regelmäßig ipcrm aufrufen musste, um die Überreste eines abgestürzten Prozesses zu bereinigen.

    Benutzer678269

    3. Januar 2014 um 22:32 Uhr

1397440cookie-checkWie man auf das Beenden von Nicht-Kind-Prozessen wartet

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy