【问题标题】:fork() multiple times with a timer使用计时器多次 fork()
【发布时间】:2020-05-27 20:55:49
【问题描述】:

我有这段代码:

    int pidArr[128];
    int i=0;
    clock_t begin;
    double time_spent; 
    begin = clock();
    while(1) {
        time_spent = (double)(clock() - begin) / CLOCKS_PER_SEC; 
        if (time_spent>=2.0){ break; }
        pid = fork();
        if(pid == 0){
            pidArr[i] = getpid();
            i++;
        }
    }

我想 fork() 2 秒来填充我的 pid 数组并从循环中中断,但它没有发生,我的虚拟机严重崩溃。

如果能帮我解决这个问题,我将不胜感激。

【问题讨论】:

  • 您正在创建指数级数量的进程,最有可能导致系统资源枯竭。
  • 还有什么要求?看看 2 秒内运行了多少个分叉?
  • 你在那里写了一个非常有效的分叉炸弹。您可能希望父进程在分叉第一个子进程后不要继续分叉。
  • 好吧,即使每个进程只派生一次,这样进程的数量就会随着时间线性增长,你可能会在 2秒到了。但是正如你所拥有的,随着循环的每次迭代,进程的数量会翻倍,因为父子进程都会继续分叉,所以你有非常快速的指数增长。你的虚拟机崩溃并不奇怪。
  • 这是一些 CS 课程中非常传统的作业。根据你的观点,它的其他名称是 tough lovehazing。在学生在共享工作站上的计算机实验室工作的日子里,分叉作业的那一周总是学期中最糟糕的一周,因为学生们经常让机器崩溃,并且重新启动需要一段时间。

标签: c linux time fork


【解决方案1】:

你不小心创建了一个 fork 炸弹,问题是当计时器结束时你应该杀死所有的进程(或者用这个 pidarr 做任何你想做的事情并在杀死所有线程之后),就像这个例子

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>

// maybe there is a standard macro or something like that
// but on my machine in /proc/sys/kernel/pid_max there is 4194304
#define PID_MAX 4194304

pid_t pidarr[PID_MAX];

static void
sigalrmHandler(int sig)
{
  for(int i = 1; i <= PID_MAX; i++){
    printf("Killing %ld\n",(long)pidarr[i]);
    kill(pidarr[i],SIGKILL);
  }
}

int main(void){
  struct sigaction sa;
  struct itimerval new_timer;

  pidarr[0] = getpid();

  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  sa.sa_handler = sigalrmHandler;
  if(sigaction(SIGALRM,&sa,NULL) == -1){
    perror("setting the handler");
    return 1;
  }

  new_timer.it_value.tv_sec = 2;
  new_timer.it_value.tv_usec = 0;
  new_timer.it_interval.tv_sec = 0;
  new_timer.it_interval.tv_usec = 0;

  // Create the timer
  if(setitimer(ITIMER_REAL,&new_timer,NULL) == -1){
    perror("setting the timer");
    return 1;
  }

  for(int i = 1; ;i++){
    switch(pidarr[i] = fork()){
    case -1: // ERROR
      perror("setting the timer");
      return 1;
    case 0:
      for(;;) // Waiting to die
        ;
    case 1:
      wait(NULL);
      break;
    }
  }

  return 0;
}

我使用settimer() (https://www.man7.org/linux/man-pages/man3/setitimer.3p.html) 来创建一个两秒的计时器和sigaction() (https://www.man7.org/linux/man-pages/man2/sigaction.2.html) 来投射信号,当信号到达时我会杀死所有进程到pidarr 数组中,所以我的机器不会崩溃,如果计时器更大我们会遇到同样的问题,因为机器会在到达计时器之前崩溃

【讨论】:

  • 谢谢,我从你的回答中推断出了一些想法!
猜你喜欢
  • 2019-03-02
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-20
相关资源
最近更新 更多