【问题标题】:Program run in child process doesn't loop在子进程中运行的程序不循环
【发布时间】:2011-05-22 22:03:12
【问题描述】:

我有一个关于从子进程读取标准输出的父进程的具体问题。我的问题是,当我运行程序时,子程序应该在一个循环中多次执行一个新程序,但它只运行一次并退出到父进程。子进程正在运行一个将消息打印到标准输出的简单程序。 提前致谢。

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <sys/wait.h>

#define ssec 1
#define fsec 0
#define secBuf 5
#define decbase 10
#define fgbuf 60

volatile sig_atomic_t aborting = 0;


void chld_handler(int sig) {
   if (sig == SIGINT) {
      aborting++;
   }
}


int rand_start(int low, int high) {
   int s;
   int r = 0;
   srand(time(NULL));

   s = rand();

   r = s % high + low;

   return r;
}


void Usage() {
   printf("Usage :schedule [-s<seconds>] [-f<seconds>] <program> <emergency> <logfile>\n");
   exit(1);
}


int main(int argc, char *argv[]) {
   /* getopt variablen */
   int opt;
   int index;

   int sflag = 0;
   int fflag = 0;

   char *svalue;
   char *fvalue;

   int sseconds = ssec;
   int fseconds = fsec;

   char *reactor;
   char *emergency;
   char *logfile;

   /* */
   char *endptr;
   /* Pipe and child */

   int pipepc1[2];
   int pipepc2[2];

   int child1_fd;
   int child2_fd;

   FILE *log;
   FILE *pipe_reader;

   char *p;
   char *buf;
   int waitFc;
   int status;

   /* prgm */
   int prg_r;
   int prg_e;

   /* termination */
   int cnt = 0;
   int start_period;
   p = malloc(fgbuf * sizeof(char));
   buf = malloc(fgbuf * sizeof(char));

   (void)signal(SIGINT, chld_handler);

   if (argc < 4) {
      Usage();
   }
   else if (argc == 4) {
      reactor = argv[1];
      emergency = argv[2];
      logfile = argv[3];
   }
   else if (argc > 4) {
      /* argumentenbehandlung*/
      while((opt = getopt(argc, argv, ":s:f:")) != -1) {
         printf("sflag %d fflag %d \n", sflag, fflag);
         printf("opt  %c \n", opt);
         printf("optind %d \n ", optind);
         switch (opt) {

         case 's':
            if (sflag == 0) {
               sflag++;
               svalue = optarg;
            }
            else {
               fprintf(stderr, "Widerholung der option -s\n");
           Usage();
            }
            break;

         case 'f':
            if (fflag == 0) {
               fflag++;
           fvalue = optarg;
            }
            else {
               fprintf(stderr, "Widerholung der option -f\n");
           Usage();
            }
            break;

         case ':' :
            fprintf(stderr, "Option -%c brauch ein argument\n", optopt);
            Usage();
            break;

         case '?' :
            fprintf(stderr, "Nicht bekannte option -%c \n", optopt);
            Usage();
            break;

         default :
            assert(0);
         }/* switch */
      }/* while getopt */

      for (index = optind; index < argc; index++) {
         if ((argc - index) == 3) {
            reactor = argv[index];
         }
         else if ((argc - index) == 2) {
            emergency = argv[index];
         }
         else if ((argc - index) == 1) {
            logfile = argv[index];
         }
      } /* for schleife*/

      /*  */
      if (sflag) {
         sseconds = (int)strtol(svalue, &endptr, decbase);
         printf("%d ssec\n", sseconds);
      }

      if (fflag) {
         fseconds = (int)strtol(fvalue, &endptr, decbase);
         printf("%d fsec\n", fseconds);
      }
   }

   /* pipeing*/
   if (pipe(pipepc1) == -1) {
      fprintf(stderr, "Fehler bei der Erzeugung der pipe\n");
      exit(1);
   }
   else {
      printf("Pipe created\n");
   }

   /* erzeuge child1*/
   child1_fd = fork();

   if (child1_fd < 0) {
      fprintf(stderr, "Fehler beim asfuehren von fork\n");
      exit(0);
   }

   if (child1_fd == 0) {
      printf("**CHILD**\n");
      /* close pipe read*/
      if (close(pipepc1[0]) == -1) {
         fprintf(stderr, "Konnte nicht das Read-Ende vom pipepc1 schliessen\n");
         exit(1);
      }

      if (close(1) == -1) {
         fprintf(stderr, "Konnte nicht das Read-Ende vom pipepc1 schliessen\n");
         exit(1);
      }

      if (dup(pipepc1[1]) !=STDOUT_FILENO) {
         fprintf(stderr, "Das setzen des Read-Endes als stdout is Fehlgeschlagen\n");
         exit(1);
      }

      if (fseconds == 0) {
         start_period = sseconds;
      }
      else
         start_period = rand_start(sseconds, (sseconds + fseconds));

      for (cnt = 0; cnt < 5; cnt++) {
         sleep(start_period);
         fflush(stdout);
         prg_r = execl(reactor, "", NULL);
         //printf("prg_r ist %d  \n", prg_r);                                                                                                                
      }

      if (close(pipepc1[1]) == -1) {
         fprintf(stderr, "Das neue stdout konnte nich geschlossen werden\n");
         exit(1);
      }
   }
   else {
      printf("**PARENT**\n");

      log = fopen(logfile, "w");

      /* schliesse pipe read*/
      close(pipepc1[1]);

      pipe_reader = fdopen(pipepc1[0], "r");

      while ((buf = fgets(p, fgbuf, pipe_reader)) != NULL) {
         printf("from Child : %s \n", buf);
         fflush(pipe_reader);
      }

      fclose(log);

      waitFc = waitpid(child1_fd, &status, 0);

      if (waitFc == -1) {
         fprintf(stderr, "Das Warten ist fehlgeschlagen\n");
         exit(1);
      }

      printf("child is done\n und waitFc = %d\n und satus %d", waitFc, status);
      fclose(pipe_reader);
      close(pipepc1[1]);
   }

   printf("argc = %d \n", argc);
   exit(0);
}

和反应堆程序:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
   srand(time(NULL));
   int i;
   int s;

   s = rand() % 7;
   /* printf("%d \n", s);*/

   if (s != 6) {
      printf("OK\n");
      fflush(stdout);
   }
   else {
      printf("PRESSURE TOO HIGH - IMMEDIATE SHUTDOWN REQUIRED");
      exit(EXIT_FAILURE);
   }
}

【问题讨论】:

  • 如果您希望有人帮助您调试它,您确实需要精简这段代码并解释它应该做什么以及它正在做什么。
  • 好的,我很抱歉。父进程派生出一个子进程,该子进程运行由参数 提供的新程序,它应该在循环中执行。父母和孩子通过管道进行通信,而孩子的标准输出是管道的写端。父级从管道中读取并打印它。我希望这是足够的描述
  • 。 : 切入正题,如何让新程序运行我想要的时间或直到发生特定操作。

标签: c exec fork pipe


【解决方案1】:

嗯...你使用 fork() 调用来创建一个子进程,然后 execl() 来执行另一个程序。问题是 execl() 将当前进程映像(您的子进程)替换为您正在执行的命令的映像。因此,在 for() 循环的第一遍结束时,您的程序将被正在执行的命令所取代。当它完成它的工作时,它只是简单地退出,终止子进程。

我认为你需要做的是调用popen() 而不是execl()。这将导致命令在单独的进程中执行,而不是替换您当前的进程。如果您愿意,您甚至可以一次启动所有命令(循环调用 popen()),然后在子进程可用时立即使用 select()/epool() 从子进程中读取数据。

【讨论】:

  • 感谢您的建议。但是,如果我继续使用 execl 而不是 popen,我将不得不在子进程中创建一个进程,而不是在新创建的孙子进程中执行新程序,还是我会重复错误?
  • Prucina:或者当我 fork 一个孩子时,克隆它并在克隆中添加一个执行我的程序的函数?
  • 如果你愿意的话,你可以坚持使用 fork()/execl()(事实上 popen() 在底层使用了 fork()/execve()/pipe())。您必须创建另一个子进程(使用 fork(),clone() 并没有给您任何真正的优势)然后在那里调用 execl()。但是,我认为多级分叉会使您的程序有点混乱且难以阅读。在我看来,在 for() 循环中 fork() 然后在子进程中 execl() 会更好。
【解决方案2】:

它不会在子进程内循环,因为您正在执行 exec 这通常意味着它会覆盖子进程并退出。 如果你想循环,你将不得不从你的循环中产生另一个子进程,你通常只会在其中执行 exec,因此当它迭代时,它将产生一个子进程,你在其中执行 exec 它将覆盖并退出。 所以你需要做的是:-

for(cnt = 0; cnt < 5; cnt++){
    sleep(start_period);
    fflush(stdout);
    child2_fd = fork();
    if (child2_fd == 0){
       prg_r = execl(reactor,"",NULL);
    }
}

【讨论】:

    【解决方案3】:

    您正在调用反应器程序,就好像它是一个库函数一样。该答案基于您真正想要的假设。 (这里可能是一个错误的假设,但对其他人来说可能不是。)

    也就是说,您希望当前以reactor.c:main() 表示的代码块在循环中重复。您已经注意使用fork() 创建一个单独的进程。所以另一种解决方案是重组整个项目:将reactor.c 的角色指定为库(libreactor.a:reactor_func(int argc, char *argv[]),其中反应器代码被重新分解为可调用函数)而不是不透明的可执行文件(reactor:main()),并且在编译时链接到顶级可执行文件。那么execl(reactor_executable_path, args...)就变成了:reactor_func(args...)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-15
      • 1970-01-01
      • 2019-05-02
      • 1970-01-01
      • 2011-07-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多