Программа, запущенная в дочернем процессе, не зацикливается

У меня есть конкретный вопрос относительно того, как родительский процесс читает стандартный вывод от дочернего. Моя проблема в том, что когда я запускаю программу, дочерняя программа должна выполнять новую программу несколько раз в цикле, но запускает ее только один раз и выходит в родительский процесс. Дочерний процесс запускает простую программу, которая выводит сообщение на стандартный вывод. Заранее спасибо.

#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);
   }
}

person Robin    schedule 09.12.2010    source источник
comment
Вам действительно нужно урезать этот код и объяснить, что он должен делать и что делает, если вы хотите, чтобы кто-то помог вам отладить его.   -  person R.. GitHub STOP HELPING ICE    schedule 09.12.2010
comment
Хорошо, прошу прощения. Родительский процесс порождает дочерний процесс, который запускает новую программу, предоставленную аргументом ‹reactor›, и она должна выполняться в цикле. Родитель и потомок общаются по каналу, тогда как стандартный вывод дочернего является концом канала для записи. Родитель читает из канала и распечатывает его. Я надеюсь, что этого описания достаточно   -  person Robin    schedule 09.12.2010
comment
. : Чтобы перейти к делу, как мне заставить новую программу работать так долго, как я хочу, или до тех пор, пока не произойдет определенное действие.   -  person Robin    schedule 09.12.2010


Ответы (3)


Что ж ... вы используете вызов fork () для создания дочернего процесса, а затем execl () для выполнения другой программы. Проблема в том, что execl () заменяет текущий образ процесса (ваш дочерний процесс) на образ выполняемой команды. Итак, в конце первого прохода цикла for () ваша программа заменяется выполняющейся командой. Когда он завершает свою работу, он просто завершает работу, завершая дочерний процесс.

Я думаю, что вам нужно вызвать popen () вместо execl (). Это заставит команду выполняться в отдельном процессе, а не заменять текущий процесс. При желании вы даже можете запустить все команды сразу (вызов popen () в цикле), а затем использовать select () / epool () для чтения данных из дочерних процессов, как только они станут доступны.

person Jacek Prucia    schedule 09.12.2010
comment
Спасибо за совет. Но если бы я продолжил использовать execl вместо popen, мне пришлось бы создать процесс в дочернем процессе, а затем выполнить новую программу во вновь созданном внуке, или я просто повторю ошибку? - person Robin; 09.12.2010
comment
Пруцина: Или, может быть, когда я создаю форк ребенка, клонирую его и добавляю в клон функцию, которая выполняет мою программу? - person Robin; 09.12.2010
comment
Вы можете придерживаться fork () / execl (), если хотите (на самом деле popen () использует fork () / execve () / pipe () под капотом). Вам нужно будет создать еще один дочерний процесс (использование fork (), clone () не дает вам никаких реальных преимуществ), а затем вызвать execl () там. Однако я думаю, что несколько уровней разветвления сделают вашу программу немного запутанной и трудной для чтения. Мне кажется, что лучше будет fork () внутри цикла for (), а затем execl () внутри дочернего процесса. - person Jacek Prucia; 09.12.2010

Он не будет зацикливаться внутри дочернего процесса, потому что вы выполняете 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);
    }
}
person rstalekar    schedule 07.03.2018

Вы вызываете программу реактора, как если бы это была библиотечная функция. Этот ответ основан на предположении, что вы действительно этого хотели. (Возможно, здесь ошибочное предположение, но, возможно, не для других.)

То есть вы хотите, чтобы блок кода, в настоящее время выраженный в reactor.c:main(), повторялся в цикле. Вы уже позаботились о создании отдельного процесса с fork(). Таким образом, другим решением является реструктуризация всего проекта: назначить роль reactor.c как библиотеки (libreactor.a:reactor_func(int argc, char *argv[]), где код реактора повторно преобразован в вызываемую функцию), а не как непрозрачный исполняемый файл (reactor:main()), и связать во время компиляции с верхний исполняемый файл. Тогда execl(reactor_executable_path, args...) становится просто: reactor_func(args...).

person BaseZen    schedule 31.05.2021