我已经完成了一个C程序,它产生了许多进程,然后在很短的时间内杀死它们。我是新手,并试图弄清楚为什么我试图跟踪我的进程来杀死作品。我的指针pid_t* id
指向cmd line参数创建时要求的进程ID数。
现在这是我的窘境。 fork()返回child和parent的值,但是我找不到它是如何工作的固定顺序。它是先返回子值还是父值,还是未定义?
每个衍生进程的id[]
数组是相同的(正如没有生成n_child数组的那样)?
由于程序100%的时间都在工作,所以看起来父总是最后返回,因为这是在终止过程中存储在数组中的内容。这是一种“安全”的方式来跟踪流程(请记住,我不是在寻找最佳方式或任何东西,因为我确信有更好的方法)?似乎答案应该是否定的,如果我确定它是父母,我应该只设置数组。
以下是代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#define MAX_N_CHILD 10
int main (int argc, char **argv) {
int n_child, i;
pid_t* id;
/* note: on a 32 bit machine, pid_t is defined as the __S32_TYPE,
which is an int rather than a long */
if (argc == 2) {
n_child = atoi (argv[1]); /* captures the command line argument */
/* **NOTE** argv[0] is always the file name of this program */
if (n_child > MAX_N_CHILD) {
printf ("Too many children wanted!\n");
return 0;
}
}
else {
printf ("Invalid number of arguments!\n");
return 0;
}
id = malloc( sizeof(pid_t) * n_child );
if(id == NULL)
{
return 0;
}
printf ("******** HELLO! *********\n");
printf ("parent %d(CPU#%d)\n", getpid(), sched_getcpu());
/* create new process(es) */
for(i = 0; i < n_child; ++i)
{
id[i] = fork();
if (id[i] == -1)
{
printf("Error: Process not created");
return 0;
}
else if (id[i] == 0) { /* I'm the child */
//execlp ("./dummy", "dummy", NULL); /* replace myself with a new program */
sleep(2);
}
else
{
continue; //Continue loop
}
} //End for
/* Only the parent process should get here. */
/* wait a little to let the child processes run before killing them */
usleep(50000); /* sleep for 50000 microseconds */
/* kill */
for(i = 0; i < n_child; ++i)
{
printf ("killing %d\n", id[i]);
kill (id[i], SIGKILL); /* SIGKILL is defined in signal.h */
}
//pkill -TERM -P id //Only kills immediate children of parent
printf ("All %d child processes killed!\n", n_child);
}
答案 0 :(得分:5)
嗯......不......不完全。现在这是我的窘境。 fork()返回child和parent的值,但是我找不到它是如何工作的固定顺序。它是先返回子值还是父值,还是未定义?
以下是fork
(有效)中发生的事情:
fork
会返回0
。fork
返回子项的新pid。来自fork
的两个回复同时发生,在过程的两个不同副本中。实际上,它们之间的唯一区别是它们从fork
得到的结果。
没有排序:这几乎肯定是在同一时刻在两个CPU内核上,甚至在单核系统上,它们将出现在任意中命令并且可能一次执行单个机器代码指令,与另一个交错。
换句话说,订单明确定义为同步。
在fork
的那一刻,有两份副本。所以,一方面,是,现在存在数组id[]
的 n 副本;但是,每个孩子的副本只会有之前产生的孩子的身份(甚至不是自己的)。
用exec
替换execlp
(在这种情况下为sleep
)导致程序徘徊在......非常奇怪的领域。您编写/* Only the parent process should get here */
,但 与sleep
一致。
使用exec
*函数,您可以销毁进程的内容并使用新程序替换它(保持其pid和其他一些属性)。假设exec
没有失败,那么这是真的,你的程序将不再是子进程中的程序,并且不会达到该行;
然而,正如所写,你有一个好奇的竞争条件。 sleep
和usleep
可以设置程序花费时间的下限,但如果由于任何原因父进程移动速度不足以杀死其子进程,则子进程将开始尝试到(编辑忘记这一点)完成for
循环并产生更多的孩子,然后互相杀死他们的新孩子。由于每个孩子的id[]
在fork
编辑之前被复制,因此它会尝试杀死所有“兄弟姐妹”,然后为自己和其产生的其他孩子杀死pid = 0。 / p>
您还提到在您的问题中生成线程,但您的问题代码中的任何内容都与线程无关。
答案 1 :(得分:2)
我在这里看到一个问题。这一行:
execlp ("./dummy", "dummy", NULL); /* replace myself with a new program */
在您的原始计划中非常重要。如果它被注释掉,孩子将继续循环并在循环中产生它自己的子子。因此,您将创建(n *(n-1))/ 2个进程,然后以不可预测的方式退出或被杀死。
你的时间也非常紧张。尝试使用数十秒的延迟,以便您可以手动查看系统中发生的情况。
否则该程序对我来说似乎没问题。
关于创建新进程后的执行顺序,它以与其父进程相同的方式竞争CPU。所以基本上是不可预测的,哪一个将首先运行多长时间。如果CPU中有多个内核,它们实际上可以同时运行。
答案 2 :(得分:1)
当您调用fork
时,父进程和子进程都有自己的所有变量副本;它有效地创建父进程的快照并将其复制到子进程。这两个进程各自独立运行,fork
函数同时在两个进程中返回;在父级中,它返回子级的PID,在子级中返回0。
所以排序无关紧要。每个进程都有自己的id
数组,并将它们分配给id[i]
的私有副本。