Wir werden Zombies mit dem vom Pharmaunternehmen Umbrella entwickelten T-Virus herstellen. Das ist ein Witz, und ich zeige Ihnen, wie Sie in C einen Zombie-Prozess erstellen, vermeiden und ausführen.
Ein Zombie-Prozess ist ein untergeordneter Prozess, bei dem der übergeordnete Prozess den untergeordneten Prozess in Ruhe lässt und nicht auf unbestimmte Zeit beendet werden kann.
[vagrant@vagrant-centos65 ~]$ cat /etc/redhat-release
CentOS release 6.5 (Final)
zombie.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
pid_t pid;
//Argumentprüfung
if (argc != 3) {
fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
exit(1);
}
//Gabel, um einen untergeordneten Prozess zu erstellen
//Für die Verarbeitung nach dem Verzweigen werden zwei Prozesse gleichzeitig ausgeführt, ein übergeordneter Prozess und ein untergeordneter Prozess.
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork(2) failed\n");
exit(1);
}
//Der Rückgabewert von fork des untergeordneten Prozesses ist 0
if (pid == 0) { /*Was der untergeordnete Prozess tut*/
execl(argv[1], argv[1], argv[2], NULL);
/* execl()Wird bei Erfolg nicht zurückgegeben, daher schlägt bei Rückgabe alles fehl*/
perror(argv[1]);
exit(99);
}
//Der Rückgabewert der Verzweigung des übergeordneten Prozesses ist die Prozess-ID des untergeordneten Prozesses.
else { /*Was der übergeordnete Prozess tut*/
//Die Überlebenszeit der Zombies beträgt 30 Sekunden
//Ich habe es hier auf 30 Sekunden eingestellt, aber während(1)Im Falle einer Endlosschleife wie gibt es immer Zombies
sleep(30);
printf("child (PID=%d) finished;\n", pid);
exit(0);
}
}
Argument 1: Vollständiger Pfad des auszuführenden Befehls (diesmal / bin / echo
)
Argument 2: Parameter für den Befehl von Argument 1 (diesmal This is zombie
)
Wenn Sie wie folgt ausführen, wird die Eingabeaufforderung 30 Sekunden lang nicht zurückgegeben, und Sie können die Existenz von Zombies auf demselben Terminal nicht bestätigen. (Wenn Sie die Zombies überprüfen möchten, indem Sie ein anderes Terminal anheben, können Sie die folgende Methode verwenden.)
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie ./zombie.c
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie"
This is zombie //→ Es gibt Effekte wie das Warten von 30 Sekunden in diesem Zustand und die Unfähigkeit, andere Arbeiten auszuführen.
child (PID=24579) finished; //→ Wird nach 30 Sekunden angezeigt
[vagrant@vagrant-centos65 tmp]$
Fügen Sie daher & am Ende des Befehls wie unten gezeigt hinzu und führen Sie ihn im Hintergrund aus. Wir bestätigen auch die Existenz von Zombies mit dem Befehl ps während der 30 Sekunden, in denen Zombies existieren. Sie können bestätigen, dass es sich um einen Zombie handelt, da im Ergebnis des Befehls ps "defunct" angezeigt wird.
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 24601
[vagrant@vagrant-centos65 tmp]$ This is zombie
//→ Wenn Sie die Eingabetaste nicht drücken, wird die Eingabeaufforderung nicht zurückgegeben. Drücken Sie daher die Eingabetaste
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
vagrant 24602 0.0 0.0 0 0 pts/0 Z 23:06 0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ child (PID=24602) finished; //→ Wird nach 30 Sekunden angezeigt
//→ Wenn Sie die Eingabetaste nicht drücken, wird die Eingabeaufforderung nicht zurückgegeben. Drücken Sie daher die Eingabetaste
[1]+ Done ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
Nach dem Verzweigen verwendet der übergeordnete Prozess waitpid, um die Beendigung des untergeordneten Prozesses abzufangen. Es liegt in der Verantwortung der Eltern, das Auftreten von Zombies zu verhindern.
zombie_avoid1.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
pid_t pid;
//Argumentprüfung
if (argc != 3) {
fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
exit(1);
}
//Gabel, um einen untergeordneten Prozess zu erstellen
//Für die Verarbeitung nach dem Verzweigen werden zwei Prozesse gleichzeitig ausgeführt, ein übergeordneter Prozess und ein untergeordneter Prozess.
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork(2) failed\n");
exit(1);
}
//Der Rückgabewert von fork des untergeordneten Prozesses ist 0
if (pid == 0) { /*Was der untergeordnete Prozess tut*/
execl(argv[1], argv[1], argv[2], NULL);
/* execl()Wird bei Erfolg nicht zurückgegeben, daher schlägt bei Rückgabe alles fehl*/
perror(argv[1]);
exit(99);
}
//Der Rückgabewert der Verzweigung des übergeordneten Prozesses ist die Prozess-ID des untergeordneten Prozesses.
else { /*Was der übergeordnete Prozess tut*/
int status;
waitpid(pid, &status, 0);
sleep(30);
printf("child (PID=%d) finished; ", pid);
if (WIFEXITED(status))
printf("exit, status=%d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("signal, sig=%d\n", WTERMSIG(status));
else
printf("abnormal exit\n");
exit(0);
}
}
Sie können mit dem Befehl ps bestätigen, dass der Zombie nicht existiert.
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid1 ./zombie_avoid1.c
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid1 /bin/echo "This is zombie" &
[1] 24619
[vagrant@vagrant-centos65 tmp]$ This is zombie
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ child (PID=24620) finished; exit, status=0
[1]+ Done ./zombie_avoid1 /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
Erstellen Sie einen untergeordneten Prozess aus einem übergeordneten Prozess und einen Enkelprozess aus einem untergeordneten Prozess. Durch das Beenden des untergeordneten Prozesses wird der Enkelprozess nicht zu einem Zombie, da der übergeordnete Prozess aus dem Enkelprozess nicht mehr vorhanden ist. Stellen Sie sicher, dass der Enkelprozess noch vorhanden ist, wenn der übergeordnete und der untergeordnete Prozess beendet werden.
Prozess | Prozessの終了時間 |
---|---|
Übergeordneter Prozess | Beenden Sie nach 30 Sekunden |
Untergeordneter Prozess | Sofortiges Ende |
Enkelprozess | Beenden Sie nach 60 Sekunden |
zombie_avoid2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
pid_t pid;
//Argumentprüfung
if (argc != 3) {
fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
exit(1);
}
//Gabel, um einen untergeordneten Prozess zu erstellen
//Für die Verarbeitung nach dem Verzweigen werden zwei Prozesse gleichzeitig ausgeführt, ein übergeordneter Prozess und ein untergeordneter Prozess.
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork(2) failed\n");
exit(1);
}
//Der Rückgabewert von fork des untergeordneten Prozesses ist 0
if (pid == 0) { /*Was der untergeordnete Prozess tut*/
pid_t pid_child;
pid_child = fork();
if (pid_child < 0) {
fprintf(stderr, "child fork(2) failed\n");
exit(1);
}
if (pid_child == 0) { /*Was der Enkelprozess macht*/
execl(argv[1], argv[1], argv[2], NULL);
/* execl()Wird bei Erfolg nicht zurückgegeben, daher schlägt bei Rückgabe alles fehl*/
perror(argv[1]);
exit(99);
} else { /*Was der untergeordnete Prozess tut*/
printf("grandchild (PID=%d) finished; ", pid_child);
exit(0);
}
}
//Der Rückgabewert der Verzweigung des übergeordneten Prozesses ist die Prozess-ID des untergeordneten Prozesses.
else { /*Was der übergeordnete Prozess tut*/
int status;
waitpid(pid, &status, 0);
sleep(30);
printf("child (PID=%d) finished; ", pid);
if (WIFEXITED(status))
printf("exit, status=%d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("signal, sig=%d\n", WTERMSIG(status));
else
printf("abnormal exit\n");
exit(0);
}
}
Dieses Mal verwende ich "Schlaf" anstelle von "Echo", um die Existenz eines Enkelprozesses zu überprüfen.
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid2 ./zombie_avoid2.c
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid2 /bin/sleep 60 &
[1] 25674
[vagrant@vagrant-centos65 tmp]$ grandchild (PID=25676) finished;
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$
//Zombies gibt es nicht
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
//Der Enkelprozess existiert
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
vagrant 25676 0.0 0.1 100924 620 pts/0 S 01:29 0:00 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$ child (PID=25675) finished; exit, status=0
[1]+ Done ./zombie_avoid2 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$
//Der Enkelprozess ist auch dann noch vorhanden, wenn der übergeordnete Prozess beendet wird
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
vagrant 25676 0.0 0.1 100924 620 pts/0 S 01:29 0:00 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$
//Der Enkelprozess endet ebenfalls nach 60 Sekunden
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
[vagrant@vagrant-centos65 tmp]$
zombie_avoid3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
static void detach_children(void);
static void noop_handler(int sig);
int
main(int argc, char *argv[])
{
pid_t pid;
//Argumentprüfung
if (argc != 3) {
fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
exit(1);
}
detach_children();
//Gabel, um einen untergeordneten Prozess zu erstellen
//Für die Verarbeitung nach dem Verzweigen werden zwei Prozesse gleichzeitig ausgeführt, ein übergeordneter Prozess und ein untergeordneter Prozess.
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork(2) failed\n");
exit(1);
}
//Der Rückgabewert von fork des untergeordneten Prozesses ist 0
if (pid == 0) { /*Was der untergeordnete Prozess tut*/
execl(argv[1], argv[1], argv[2], NULL);
/* execl()Wird bei Erfolg nicht zurückgegeben, daher schlägt bei Rückgabe alles fehl*/
perror(argv[1]);
exit(99);
}
//Der Rückgabewert der Verzweigung des übergeordneten Prozesses ist die Prozess-ID des untergeordneten Prozesses.
else { /*Was der übergeordnete Prozess tut*/
printf("child (PID=%d) finished;\n", pid);
//Da das Signal im Schlaf gefangen ist, wird es währenddessen unendlich wiederholt
while(1);
exit(0);
}
}
static void
detach_children(void)
{
struct sigaction act;
act.sa_handler = noop_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART | SA_NOCLDWAIT;
if (sigaction(SIGCHLD, &act, NULL) < 0) {
printf("sigaction() failed: %s", strerror(errno));
}
}
static void
noop_handler(int sig)
{
;
}
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid3 ./zombie_avoid3.c
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid3 /bin/echo "This is zombie" &
[1] 25895
[vagrant@vagrant-centos65 tmp]$ child (PID=25896) finished;
This is zombie
[vagrant@vagrant-centos65 tmp]$
//Zombies gibt es nicht
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
// zombie_Vermeiden3-Prozess existiert
[vagrant@vagrant-centos65 tmp]$ ps aux | grep zombie_avoid3 | grep -v grep
vagrant 25895 102 0.0 3924 448 pts/0 R 02:42 0:13 ./zombie_avoid3 /bin/echo This is zombie
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ kill 25895
[vagrant@vagrant-centos65 tmp]$
[1]+ Terminated ./zombie_avoid3 /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
Ich werde Ihnen zeigen, wie Sie den in zombie.c
erstellten Zombie-Prozess beenden können.
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 25932
[vagrant@vagrant-centos65 tmp]$ This is zombie
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant 25932 0.0 0.0 3920 372 pts/0 S 02:47 0:00 ./zombie /bin/echo This is zombie
vagrant 25933 0.0 0.0 0 0 pts/0 Z 02:47 0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$
//Töte Zombies
[vagrant@vagrant-centos65 tmp]$ kill 25933
//Du hast einen Zombie getötet, aber der Zombie existiert
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant 25932 0.0 0.0 3920 372 pts/0 S 02:47 0:00 ./zombie /bin/echo This is zombie
vagrant 25933 0.0 0.0 0 0 pts/0 Z 02:47 0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ child (PID=25933) finished;
[1]+ Done ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 25965
[vagrant@vagrant-centos65 tmp]$ This is zombie
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant 25965 0.0 0.0 3920 372 pts/0 S 02:50 0:00 ./zombie /bin/echo This is zombie
vagrant 25966 0.0 0.0 0 0 pts/0 Z 02:50 0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$
//Beenden Sie den übergeordneten Prozess
[vagrant@vagrant-centos65 tmp]$ kill 25965
[vagrant@vagrant-centos65 tmp]$
[1]+ Terminated ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
//Es gibt keine übergeordneten Prozesse oder Zombies
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
[vagrant@vagrant-centos65 tmp]$
[Normale Linux-Programmierung 2. Ausgabe: Der königliche Weg der gcc-Programmierung, der aus dem Mechanismus von Linux gelernt werden kann](https://www.amazon.co.jp/%E3%81%B5%E3%81%A4%E3%81%86% E3% 81% AELinux% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0-% E7 % AC% AC2% E7% 89% 88-Linux% E3% 81% AE% E4% BB% 95% E7% B5% 84% E3% 81% BF% E3% 81% 8B% E3% 82% 89% E5 % AD% A6% E3% 81% B9% E3% 82% 8Bgcc% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83 % B3% E3% 82% B0% E3% 81% AE% E7% 8E% 8B% E9% 81% 93-% E9% 9D% 92% E6% 9C% A8-% E5% B3% B0% E9% 83 % 8E-ebook / dp / B075ST51Y5)
So erstellen Sie einen Zombie-Prozess double fork to avoid zombie process