使用 fork() 和 execlp() 在 C 中创建进程层次结构
Using fork() and execlp() to create process hierarchy in C
我必须使用 fork() 和 execlp() 来创建和注释给定的进程层次结构:
当每个进程都应该被分叉以反映这种层次结构时,我无法全神贯注,再加上不可协商的 execlp()
的使用,它取代了当前的进程映像。
这是我设法想出的(请原谅非常非 DRY 代码,我对这些概念不熟悉):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define oops(m) {perror(m); exit(EXIT_FAILURE);}
int main() {
pid_t pid1_1, pid1_2, pid1_1_1, pid1_1_2, pid1_2_1, pid1_2_2;
pid1_1 = fork();
if (pid1_1 < 0) {
oops("Fork Failed!");
}
// child 1.1
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.1.1
pid1_1_1 = fork();
if (pid1_1_1 < 0) {
oops("Fork Failed!");
}
if (pid1_1_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.1", NULL) < 0)
oops("Execlp Failed!");
}
//grandchild 1.1.2
pid1_1_2 = fork();
if (pid1_1_2 < 0) {
oops("Fork Failed!");
}
if (pid1_1_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.2", NULL) < 0)
oops("Execlp Failed!");
}
}
pid1_2 = fork();
if (pid1_2 < 0) {
oops("Fork Failed!");
}
// child 1.2
if (pid1_2 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.2", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.2.1
pid1_2_1 = fork();
if (pid1_2_1 < 0) {
oops("Fork Failed!");
}
if (pid1_2_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.1", NULL) < 0)
oops("Execlp Failed!");
}
// grandchild 1.2.2
pid1_2_2 = fork();
if (pid1_2_2 < 0) {
oops("Fork Failed!");
}
if (pid1_2_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.2", NULL) < 0)
oops("Execlp Failed!");
}
}
// pid > 0 ==> must be parent
printf("I am the parent %d\n", getpid());
/* parent will wait for the child to complete */
if (waitpid(-1, NULL, 0) < 0)
printf("-1 from wait() with errno = %d\n", errno);
printf("Child terminated; parent exiting\n");
exit(EXIT_SUCCESS);
}
我的输出显示此层次结构设置不正确。例如,手动单步执行 gdb 并完成 1.2 的 PID 会终止整个进程树(此时应完整保留 1.1 子树)。
对于我在逻辑上复制此流程层次结构时哪里出错的任何建议,我们将不胜感激。谢谢!
Any suggestions for where I'm going wrong with logically replicating this process hierarchy would be really appreciated.
在程序开始时检查这部分代码:
pid1_1 = fork();
这将派生一个子进程。在此之后你正在做:
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
......
这意味着,现在子进程映像将被另一个进程映像替换。
根据您显示的图片,一个进程应该在调用 execlp()
之前分叉 2
个子进程,如果它是给定进程树中的父进程。您的代码的以下部分存在类似问题。
I cannot wrap my head around when each process should be forked in order to reflect this hierarchy, .....
仔细观察进程树,你会发现它是一棵完美的二叉树,每个内部节点都有 2
个子节点,所有叶节点都在同一级别。
也就是说,每个进程都应该创建 2
子进程,然后调用 execlp()
,一旦达到给定的高度(在您的情况下为 2
),没有子进程应该进一步分叉。
我将向您展示如何创建进程层次结构,您可以添加 execlp()
调用以用其他进程映像替换当前进程映像。
add to that the non-negotiable use of execlp() which replaces the current process image.
我相信,这里的当前进程是指子进程的分叉进程,这也包括最顶层的进程(相当于树中的根)。
要将进程层次结构创建为完美二叉树,您可以这样做:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main (int argc, char *argv[]) {
int height;
if (argc != 2) {
printf ("Invalid number of arguments, exiting..\n");
exit (0);
}
height = atoi (argv[1]);
if (height < 0) {
printf ("Invalid input.\n"); // error handling can be better
exit (0);
}
printf ("Parent process, my pid = %d, height = %d\n", getpid(), height);
for (int i = 0; i < height; ++i) {
printf ("\nMy pid : %d, current height of tree : %d, forking..\n", getpid(), i);
pid_t pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 1..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 2..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
// break the loop as the current process is done with forking 2 child process
break;
}
// ADD execlp call here
// This part of code is to just show you the hierarchy.
// If you add execlp call above then part is not needed.
while (wait(NULL) > 0);
printf ("pid %d : I am EXITING\n", getpid());
// added sleep for sequenced output, otherwise it's not needed
sleep (1);
return 0;
}
用法:./a.out <height_of_process_tree>
输出:
# ./a.out 0
Parent process, my pid = 50807, height = 0
pid 50807 : I am EXITING
# ./a.out 1
Parent process, my pid = 50808, height = 1
My pid : 50808, current height of tree : 0, forking..
My pid = 50809, [my parent : 50808], I am child 1..
My pid = 50810, [my parent : 50808], I am child 2..
pid 50810 : I am EXITING
pid 50809 : I am EXITING
pid 50808 : I am EXITING
# ./a.out 2
Parent process, my pid = 50811, height = 2
My pid : 50811, current height of tree : 0, forking..
My pid = 50812, [my parent : 50811], I am child 1..
My pid = 50813, [my parent : 50811], I am child 2..
My pid : 50812, current height of tree : 1, forking..
My pid : 50813, current height of tree : 1, forking..
My pid = 50814, [my parent : 50812], I am child 1..
My pid = 50815, [my parent : 50813], I am child 1..
My pid = 50816, [my parent : 50812], I am child 2..
My pid = 50817, [my parent : 50813], I am child 2..
pid 50814 : I am EXITING
pid 50815 : I am EXITING
pid 50816 : I am EXITING
pid 50817 : I am EXITING
pid 50812 : I am EXITING
pid 50813 : I am EXITING
pid 50811 : I am EXITING
我必须使用 fork() 和 execlp() 来创建和注释给定的进程层次结构:
当每个进程都应该被分叉以反映这种层次结构时,我无法全神贯注,再加上不可协商的 execlp()
的使用,它取代了当前的进程映像。
这是我设法想出的(请原谅非常非 DRY 代码,我对这些概念不熟悉):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define oops(m) {perror(m); exit(EXIT_FAILURE);}
int main() {
pid_t pid1_1, pid1_2, pid1_1_1, pid1_1_2, pid1_2_1, pid1_2_2;
pid1_1 = fork();
if (pid1_1 < 0) {
oops("Fork Failed!");
}
// child 1.1
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.1.1
pid1_1_1 = fork();
if (pid1_1_1 < 0) {
oops("Fork Failed!");
}
if (pid1_1_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.1", NULL) < 0)
oops("Execlp Failed!");
}
//grandchild 1.1.2
pid1_1_2 = fork();
if (pid1_1_2 < 0) {
oops("Fork Failed!");
}
if (pid1_1_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.2", NULL) < 0)
oops("Execlp Failed!");
}
}
pid1_2 = fork();
if (pid1_2 < 0) {
oops("Fork Failed!");
}
// child 1.2
if (pid1_2 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.2", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.2.1
pid1_2_1 = fork();
if (pid1_2_1 < 0) {
oops("Fork Failed!");
}
if (pid1_2_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.1", NULL) < 0)
oops("Execlp Failed!");
}
// grandchild 1.2.2
pid1_2_2 = fork();
if (pid1_2_2 < 0) {
oops("Fork Failed!");
}
if (pid1_2_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.2", NULL) < 0)
oops("Execlp Failed!");
}
}
// pid > 0 ==> must be parent
printf("I am the parent %d\n", getpid());
/* parent will wait for the child to complete */
if (waitpid(-1, NULL, 0) < 0)
printf("-1 from wait() with errno = %d\n", errno);
printf("Child terminated; parent exiting\n");
exit(EXIT_SUCCESS);
}
我的输出显示此层次结构设置不正确。例如,手动单步执行 gdb 并完成 1.2 的 PID 会终止整个进程树(此时应完整保留 1.1 子树)。
对于我在逻辑上复制此流程层次结构时哪里出错的任何建议,我们将不胜感激。谢谢!
Any suggestions for where I'm going wrong with logically replicating this process hierarchy would be really appreciated.
在程序开始时检查这部分代码:
pid1_1 = fork();
这将派生一个子进程。在此之后你正在做:
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
......
这意味着,现在子进程映像将被另一个进程映像替换。
根据您显示的图片,一个进程应该在调用 execlp()
之前分叉 2
个子进程,如果它是给定进程树中的父进程。您的代码的以下部分存在类似问题。
I cannot wrap my head around when each process should be forked in order to reflect this hierarchy, .....
仔细观察进程树,你会发现它是一棵完美的二叉树,每个内部节点都有 2
个子节点,所有叶节点都在同一级别。
也就是说,每个进程都应该创建 2
子进程,然后调用 execlp()
,一旦达到给定的高度(在您的情况下为 2
),没有子进程应该进一步分叉。
我将向您展示如何创建进程层次结构,您可以添加 execlp()
调用以用其他进程映像替换当前进程映像。
add to that the non-negotiable use of execlp() which replaces the current process image.
我相信,这里的当前进程是指子进程的分叉进程,这也包括最顶层的进程(相当于树中的根)。
要将进程层次结构创建为完美二叉树,您可以这样做:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main (int argc, char *argv[]) {
int height;
if (argc != 2) {
printf ("Invalid number of arguments, exiting..\n");
exit (0);
}
height = atoi (argv[1]);
if (height < 0) {
printf ("Invalid input.\n"); // error handling can be better
exit (0);
}
printf ("Parent process, my pid = %d, height = %d\n", getpid(), height);
for (int i = 0; i < height; ++i) {
printf ("\nMy pid : %d, current height of tree : %d, forking..\n", getpid(), i);
pid_t pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 1..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 2..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
// break the loop as the current process is done with forking 2 child process
break;
}
// ADD execlp call here
// This part of code is to just show you the hierarchy.
// If you add execlp call above then part is not needed.
while (wait(NULL) > 0);
printf ("pid %d : I am EXITING\n", getpid());
// added sleep for sequenced output, otherwise it's not needed
sleep (1);
return 0;
}
用法:./a.out <height_of_process_tree>
输出:
# ./a.out 0
Parent process, my pid = 50807, height = 0
pid 50807 : I am EXITING
# ./a.out 1
Parent process, my pid = 50808, height = 1
My pid : 50808, current height of tree : 0, forking..
My pid = 50809, [my parent : 50808], I am child 1..
My pid = 50810, [my parent : 50808], I am child 2..
pid 50810 : I am EXITING
pid 50809 : I am EXITING
pid 50808 : I am EXITING
# ./a.out 2
Parent process, my pid = 50811, height = 2
My pid : 50811, current height of tree : 0, forking..
My pid = 50812, [my parent : 50811], I am child 1..
My pid = 50813, [my parent : 50811], I am child 2..
My pid : 50812, current height of tree : 1, forking..
My pid : 50813, current height of tree : 1, forking..
My pid = 50814, [my parent : 50812], I am child 1..
My pid = 50815, [my parent : 50813], I am child 1..
My pid = 50816, [my parent : 50812], I am child 2..
My pid = 50817, [my parent : 50813], I am child 2..
pid 50814 : I am EXITING
pid 50815 : I am EXITING
pid 50816 : I am EXITING
pid 50817 : I am EXITING
pid 50812 : I am EXITING
pid 50813 : I am EXITING
pid 50811 : I am EXITING