我的程序在完成子进程后没有停止 运行
My program does not stop running after finishing child process
我现在正在学习 folk、exec 等,我有这段代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
pid_t childpid;
int status;
childpid=fork();
if (childpid== -1){
perror("Failed to fork\n");
exit(1);
}
if (childpid==0) {
printf("I am in child process with id = %lu\n", (long)getpid());
execvp(argv[1], &argv[1]);
perror("exec failure ");
exit(1);
}
else {
printf("I am in parent process with id = %lu\n", (long)getpid());
exit(1);
}
}
子进程工作正常,但此后由于某种原因程序继续 运行 没有做任何事情。它从不打印“我在 id = ... 的子进程中”或“我在 id = ... 的父进程中”。就像它永远不会进入父进程一样。你知道为什么吗?提前致谢
来自我的最高评论...
您正在创建一个僵尸进程。这是因为 parent 进程没有等待 child 完成。
parent 进程将[相对] 快速终止。因此,child 失去了它的 parent 并变成了僵尸。僵尸将被内核重新parent作为进程1的child(例如systemd
或initd
)。
要修复,请在最后的 printf
之后添加:wait(NULL);
更新:
Therefore do I need to always put wait(NULL) in these types of situations?
TL;DR 是......是的!
这是您通常希望对大多数程序执行的操作。
您 想要创建僵尸的少数情况之一是(例如)如果您是服务器程序(例如 inetd
)。
服务器想要运行“分离”。也就是说,作为 init 进程的 child(例如 systemd
、initd
等)。系统上只有一个 init 进程。
所有其他进程都是 children of init,即使是间接的。例如,您的程序的进程层次结构类似于:
init -> window_manager -> xterm -> bash -> your_program
无论如何,现在大多数服务器程序都是由 systemd
直接启动的。它检查一些配置文件并根据这些配置选项启动。所以,现在,大多数服务器程序不需要做任何特别的事情。
但是,如果您正在测试自己的服务器,从命令行调用它,并希望它在后台 运行 [分离],你可能会这样做:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
int opt_d;
int
main(int argc, char **argv)
{
char *cp;
pid_t childpid;
int status;
// skip over program name
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'd':
opt_d = 1;
break;
}
}
// detach into background
if (opt_d) {
childpid = fork();
if (childpid == -1) {
perror("Failed to detach\n");
exit(1);
}
// exit the parent -- child is now detached [and a zombie] and a child
// of the init process
if (childpid != 0)
exit(0);
}
childpid = fork();
if (childpid == -1) {
perror("Failed to fork\n");
exit(1);
}
if (childpid == 0) {
printf("I am in child process with id = %lu\n", (long) getpid());
execvp(*argv, argv);
perror("exec failure ");
exit(1);
}
printf("I am in parent process with id = %lu\n", (long) getpid());
wait(&status);
return 0;
}
我现在正在学习 folk、exec 等,我有这段代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
pid_t childpid;
int status;
childpid=fork();
if (childpid== -1){
perror("Failed to fork\n");
exit(1);
}
if (childpid==0) {
printf("I am in child process with id = %lu\n", (long)getpid());
execvp(argv[1], &argv[1]);
perror("exec failure ");
exit(1);
}
else {
printf("I am in parent process with id = %lu\n", (long)getpid());
exit(1);
}
}
子进程工作正常,但此后由于某种原因程序继续 运行 没有做任何事情。它从不打印“我在 id = ... 的子进程中”或“我在 id = ... 的父进程中”。就像它永远不会进入父进程一样。你知道为什么吗?提前致谢
来自我的最高评论...
您正在创建一个僵尸进程。这是因为 parent 进程没有等待 child 完成。
parent 进程将[相对] 快速终止。因此,child 失去了它的 parent 并变成了僵尸。僵尸将被内核重新parent作为进程1的child(例如systemd
或initd
)。
要修复,请在最后的 printf
wait(NULL);
更新:
Therefore do I need to always put wait(NULL) in these types of situations?
TL;DR 是......是的!
这是您通常希望对大多数程序执行的操作。
您 想要创建僵尸的少数情况之一是(例如)如果您是服务器程序(例如 inetd
)。
服务器想要运行“分离”。也就是说,作为 init 进程的 child(例如 systemd
、initd
等)。系统上只有一个 init 进程。
所有其他进程都是 children of init,即使是间接的。例如,您的程序的进程层次结构类似于:
init -> window_manager -> xterm -> bash -> your_program
无论如何,现在大多数服务器程序都是由 systemd
直接启动的。它检查一些配置文件并根据这些配置选项启动。所以,现在,大多数服务器程序不需要做任何特别的事情。
但是,如果您正在测试自己的服务器,从命令行调用它,并希望它在后台 运行 [分离],你可能会这样做:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
int opt_d;
int
main(int argc, char **argv)
{
char *cp;
pid_t childpid;
int status;
// skip over program name
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'd':
opt_d = 1;
break;
}
}
// detach into background
if (opt_d) {
childpid = fork();
if (childpid == -1) {
perror("Failed to detach\n");
exit(1);
}
// exit the parent -- child is now detached [and a zombie] and a child
// of the init process
if (childpid != 0)
exit(0);
}
childpid = fork();
if (childpid == -1) {
perror("Failed to fork\n");
exit(1);
}
if (childpid == 0) {
printf("I am in child process with id = %lu\n", (long) getpid());
execvp(*argv, argv);
perror("exec failure ");
exit(1);
}
printf("I am in parent process with id = %lu\n", (long) getpid());
wait(&status);
return 0;
}