跟踪Unix中的子进程

时间:2014-02-01 10:53:49

标签: c unix fork

我已经完成了一个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);
}

3 个答案:

答案 0 :(得分:5)

  

现在这是我的窘境。 fork()返回child和parent的值,但是我找不到它是如何工作的固定顺序。它是先返回子值还是父值,还是未定义?

嗯......不......不完全。

以下是fork(有效)中发生的事情:

  • 您的单个​​进程克隆到相同的子进程中。几乎所有的属性都被复制了。
  • 但是,子进程将具有新的进程ID(pid)
  • 在子流程中, fork会返回0
  • 在父进程中, fork返回子项的新pid。

来自fork的两个回复同时发生在过程的两个不同副本中。实际上,它们之间的唯一区别是它们从fork得到的结果。

没有排序:这几乎肯定是在同一时刻在两个CPU内核上,甚至在单核系统上,它们将出现在任意中命令并且可能一次执行单个机器代码指令,与另一个交错。

换句话说,订单明确定义为同步。

fork的那一刻,有两份副本。所以,一方面,,现在存在数组id[] n 副本;但是,每个孩子的副本只会有之前产生的孩子的身份(甚至不是自己的)。

exec替换execlp(在这种情况下为sleep)导致程序徘徊在......非常奇怪的领域。您编写/* Only the parent process should get here */,但 sleep一致。

使用exec *函数,您可以销毁进程的内容并使用新程序替换它(保持其pid和其他一些属性)。假设exec没有失败,那么这是真的,你的程序将不再是子进程中的程序,并且不会达到该行;

然而,正如所写,你有一个好奇的竞争条件。 sleepusleep可以设置程序花费时间的下限,但如果由于任何原因父进程移动速度不足以杀死其子进程,则子进程将开始尝试到(编辑忘记这一点)完成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]的私有副本。