setpgid
POSIX C-Prozessgruppen-Minimalbeispiel
Ein minimal ausführbares Beispiel für die zugrunde liegende API könnte das Verständnis erleichtern.
Dies zeigt, wie das Signal an das untergeordnete Element gesendet wird, wenn das untergeordnete Element seine Prozessgruppe nicht mit geändert hat setpgid
.
Haupt c
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
volatile sig_atomic_t is_child = 0;
void signal_handler(int sig) {
char parent_str[] = "sigint parent\n";
char child_str[] = "sigint child\n";
signal(sig, signal_handler);
if (sig == SIGINT) {
if (is_child) {
write(STDOUT_FILENO, child_str, sizeof(child_str) - 1);
} else {
write(STDOUT_FILENO, parent_str, sizeof(parent_str) - 1);
}
}
}
int main(int argc, char **argv) {
pid_t pid, pgid;
(void)argv;
signal(SIGINT, signal_handler);
signal(SIGUSR1, signal_handler);
pid = fork();
assert(pid != -1);
if (pid == 0) {
is_child = 1;
if (argc > 1) {
/* Change the pgid.
* The new one is guaranteed to be different than the previous, which was equal to the parent's,
* because `man setpgid` says:
* > the child has its own unique process ID, and this PID does not match
* > the ID of any existing process group (setpgid(2)) or session.
*/
setpgid(0, 0);
}
printf("child pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)getpgid(0));
assert(kill(getppid(), SIGUSR1) == 0);
while (1);
exit(EXIT_SUCCESS);
}
/* Wait until the child sends a SIGUSR1. */
pause();
pgid = getpgid(0);
printf("parent pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)pgid);
/* man kill explains that negative first argument means to send a signal to a process group. */
kill(-pgid, SIGINT);
while (1);
}
GitHub Upstream .
Kompilieren mit:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -Wpedantic -o setpgid setpgid.c
Laufen Sie ohne setpgid
Ohne CLI-Argumente setpgid
wird Folgendes nicht ausgeführt:
./setpgid
Mögliches Ergebnis:
child pid, pgid = 28250, 28249
parent pid, pgid = 28249, 28249
sigint parent
sigint child
und das Programm hängt.
Wie wir sehen können, ist die pgid beider Prozesse dieselbe, da sie vererbt wird fork
.
Dann, wann immer Sie schlagen:
Ctrl + C
Es gibt wieder aus:
sigint parent
sigint child
Dies zeigt, wie:
- um mit ein Signal an eine ganze Prozessgruppe zu senden
kill(-pgid, SIGINT)
- Strg + C auf dem Terminal sendet standardmäßig einen Kill an die gesamte Prozessgruppe
Beenden Sie das Programm, indem Sie an beide Prozesse ein anderes Signal senden, z Ctrl + \
. B. SIGQUIT mit .
Laufen Sie mit setpgid
Wenn Sie mit einem Argument laufen, zB:
./setpgid 1
dann ändert das Kind seine pgid, und jetzt wird jedes Mal nur ein einziges Zeichen vom Elternteil gedruckt:
child pid, pgid = 16470, 16470
parent pid, pgid = 16469, 16469
sigint parent
Und jetzt, wann immer Sie schlagen:
Ctrl + C
Nur der Elternteil empfängt das Signal ebenfalls:
sigint parent
Sie können die Eltern weiterhin wie bisher mit einem SIGQUIT töten:
Ctrl + \
Das Kind hat jetzt jedoch eine andere PGID und empfängt dieses Signal nicht! Dies ist ersichtlich aus:
ps aux | grep setpgid
Du musst es explizit töten mit:
kill -9 16470
Dies macht deutlich, warum Signalgruppen existieren: Andernfalls würden wir eine Reihe von Prozessen übrig haben, die ständig manuell gereinigt werden müssten.
Getestet unter Ubuntu 18.04.