Чтение из дочернего канала после разветвления застревает в цикле чтения в неизвестном месте - PullRequest
0 голосов
/ 13 декабря 2018

Я пишу программу, в которой я дважды разветвлялся, чтобы создать 2 дочерних процесса, которые отправляют информацию родителю через свои stdouts.Дети запускают программу, делая ее рекурсивной.То, что происходит, - то, что родитель, читая потомка, застревает в цикле чтения, но это не вечный цикл (есть конечный и ожидаемый результат);он просто не проходит мимо него.

        char response1[256];
        double complex r1[sizeof(workable)/sizeof(float)];
        char* thing = NULL;
        int countC1 = 1;
        int bytesread;
        char* response1Whole = NULL;

        while((bytesread = read(pipefdc1b[0],response1, 256)) > 0){
          fprintf(stderr,"PID:%d -> Reading Bytes from Child 1 Bytes read: %d\n\n", getpid(), bytesread);
          if(bytesread == 256){
            response1Whole = (char*) realloc(response1Whole, countC1*256 );
          }else{
            response1Whole = (char*) realloc(response1Whole, (countC1-1)*256+bytesread);
          }
          strcat(response1Whole, response1);

          countC1++;
          fprintf(stderr,"PID:%d -> Current Builts Input %s\n\n", getpid(), response1Whole);
        }

        fprintf(stderr,"PID:%d -> Child 1 Read\n\n", getpid());

Это фрагмент кода, который, я считаю, застревает.Он распечатывает все части «Текущий встроенный вход» и «Чтение байтов от дочернего элемента 1», но никогда не достигает части «Дочернее 1 чтение».Заметим, что есть конечный и детерминированный вывод, и то, что он читает, - это то, что ожидается, программа просто останавливается.

if(count == 1){
    fprintf(stdout,"%s", st);
    fflush(stdout);
    exit(EXIT_SUCCESS);
}

Это блок кода, который определяет вывод.Я чувствую, что здесь может быть какая-то проблема, когда он не завершает свой поток вывода должным образом, но затем он снова завершается.

Вот код от создания каналов к «проблемной» области:

int pipefdc1a[2];  //p->c1
int pipefdc1b[2];  //c1->p||

int pipefdc2a[2];  //p->c1
int pipefdc2b[2];  //c2->p

if(pipe(pipefdc1a) == -1){
  fprintf(stderr, "Pipe Creation Failed\n");
  exit(EXIT_FAILURE);
}
if(pipe(pipefdc1b) == -1){
  fprintf(stderr, "Pipe Creation Failed\n");
  exit(EXIT_FAILURE);
}
if(pipe(pipefdc2a) == -1){
  fprintf(stderr, "Pipe Creation Failed\n");
  exit(EXIT_FAILURE);
}
if(pipe(pipefdc2b) == -1){
  fprintf(stderr, "Pipe Creation Failed\n");
  exit(EXIT_FAILURE);
}
//fprintf(stderr,"PID:%d -> Pipes Created\n\n", getpid());
fflush(stdout);
pid_t pid = fork();
pid_t pid2;

switch (pid) {
  case -1:

    fprintf(stderr, "Cannot fork!\n");
    exit(EXIT_FAILURE);
  case 0:
    //child 1
    close(pipefdc1a[1]);
    close(pipefdc1b[0]);
    close(pipefdc2a[0]);
    close(pipefdc2a[1]);
    close(pipefdc2b[0]);
    close(pipefdc2b[1]);

    dup2(pipefdc1a[0],STDIN_FILENO);
    close(pipefdc1a[0]);

    dup2(pipefdc1b[1], STDOUT_FILENO);
    close(pipefdc1b[1]);

    execlp("./forkFFT","forkFFT", NULL);

    exit(EXIT_FAILURE);

  default:
    //parent
    fflush(stdout);
    pid2 = fork();
    switch(pid2){
      case -1:
        fprintf(stderr, "Cannot fork!\n");
        exit(EXIT_FAILURE);
      case 0:
        //child 2
        //fprintf(stderr,"PID:%d -> New Child 2 Created\n\n", getpid());
        close(pipefdc1a[1]);
        close(pipefdc1a[0]);
        close(pipefdc1b[0]);
        close(pipefdc1b[1]);
        close(pipefdc2a[1]);
        close(pipefdc2b[0]);

        dup2(pipefdc2a[0],STDIN_FILENO);
        close(pipefdc2a[0]);

        dup2(pipefdc2b[1], STDOUT_FILENO);
        close(pipefdc2b[1]);

        execlp("./forkFFT","forkFFT", NULL);

        exit(EXIT_FAILURE);
      default:
        //parent


        fprintf(stderr, "entered parent switch. PID1: %d, PID2: %d\n\n", pid, pid2);

        write(pipefdc1a[1], stp1, evensize);
        write(pipefdc2a[1], stp2, oddsize);
        close(pipefdc1a[1]);
        close(pipefdc2a[1]);

        char response1[256];
        char response2[256];
        double complex r1[sizeof(workable)/sizeof(float)];
        double complex r2[sizeof(workable)/sizeof(float)];
        char* thing = NULL;
        int countC1 = 1;
        int bytesread;
        char* response1Whole = NULL;



        while((bytesread = read(pipefdc1b[0],response1, 256)) > 0){
          fprintf(stderr,"PID:%d -> Reading Bytes from Child 1 Bytes read: %d\n\n", getpid(), bytesread);
          if(bytesread == 256){
            response1Whole = (char*) realloc(response1Whole, countC1*256 );
          }else{
            response1Whole = (char*) realloc(response1Whole, (countC1-1)*256+bytesread);
          }
          strcat(response1Whole, response1);

          countC1++;
          fprintf(stderr,"PID:%d -> Current Builts Input %s\n\n", getpid(), response1Whole);
        }

        fprintf(stderr,"PID:%d -> Child 1 Read\n\n", getpid());
        char* token = strtok(response1Whole, "\n");
        while(token != NULL){
          double real = (double)strtof(token, &thing);
          if(token == thing){
            fprintf(stderr, "Real Part is NAN\n");
            exit(EXIT_FAILURE);
          }
          fprintf(stderr, "Real Number Read from child 1: %lf. PID1: %d, PID2: %d\n\n", real, pid, pid2);
          double imaginary = 0.0;
          if(thing != NULL){
            fprintf(stderr,"Thing String: %s\n", thing);
            char* check = NULL;
            imaginary = (double)strtof(thing, &check);
            if(check == thing){
              fprintf(stderr, "Imaginary Part is NAN\n");
              exit(EXIT_FAILURE);
            }
          }
          fprintf(stderr, "Imaginary part of number 1: %lf. PID1: %d, PID2: %d\n\n",imaginary, pid, pid2);
          r1[countC1] = real + imaginary*I;
          token = strtok(NULL,"\n");
        }

        fprintf(stderr, "made it 1!\n\n");

        char* thing2 = NULL;
        int countC2 = 0;
        FILE* pipe2File = fdopen(pipefdc2b[0], "r");
        while(fgets(response2, 256, pipe2File) != NULL){
          fprintf(stderr, "Reading from child 2. PID1: %d, PID2: %d\n\n", pid, pid2);

          double real = (double)strtof(response2, &thing2);
          if(response1 == thing2){
            fprintf(stderr, "Real Part is NAN\n");
            exit(EXIT_FAILURE);
          }
          fprintf(stderr, "Real Number Read from child 2: %lf. PID1: %d, PID2: %d\n\n", real, pid, pid2);
          double imaginary = 0.0;
          if(thing2 != NULL && thing2[0] != '\n'){
            fprintf(stderr,"Thing2 String: %s\n", thing2);
            char* check2 = NULL;
            imaginary = (double)strtof(thing2, &check2);
            if(check2 == thing2){
              fprintf(stderr, "Imaginary Part is NAN\n");
              exit(EXIT_FAILURE);
            }
          }
          fprintf(stderr, "Imaginary part of number 2: %lf. PID1: %d, PID2: %d\n\n",imaginary, pid, pid2);
          r2[countC2] = real + imaginary*I;
          countC2++;
        }

        fclose(pipe2File);
        fprintf(stderr, "made it 2!\n\n");

        waitpid(pid, &status, 0);
        if(status == 1){
          fprintf(stderr, "Child did not terminate normally!\n");
          exit(EXIT_FAILURE);
        }
        waitpid(pid2, &status, 0);
        if(status == 1){
          fprintf(stderr, "Child did not terminate normally!\n");
          exit(EXIT_FAILURE);
        }

Я пробовал 2 разных цикла для дочерних элементов 1 и 2, потому что в какой-то момент я решил, что это проблема, ноэто не было.

Я немного на грани моего понимания C;если бы вы могли ответить и объяснить это было бы здорово.

Я пытаюсь соблюдать правило «Минимально необходимый код», но если вы чувствуете, что требуются другие вещи, пожалуйста, спросите, и я добавлю их.

1 Ответ

0 голосов
/ 13 декабря 2018

Как я уже догадался в комментарии , вы недостаточно закрываете файловые дескрипторы - на этот раз проблема в родительском процессоре, хотя зачастую дочерние процессы не выполняют достаточное закрытие.


Правило большого пальца : Если вы dup2() один конец канала для стандартного ввода или стандартного вывода, закройте оба возвращенных дескриптора исходного файлана pipe() как можно скорее.В частности, вы должны закрыть их перед использованием любого из семейства функций exec*().

Правило также применяется, если вы дублируете дескрипторы с помощью либо dup() или fcntl() с F_DUPFD


Вы создаете 8 файловых дескрипторов с помощью вызовов 4 pipe().У детей вы закрываете их в соответствии с эмпирическим правилом.

Однако ваш родитель закрывает только 2 файловых дескриптора, прежде чем пытаться читать от детей до EOF.И, поскольку у него все еще есть конец записи каналов, которые он читает из открытого, он никогда не получит указание EOF, потому что теоретически может записать в канал.

Итак, ваш родительский код, которыйвыглядит следующим образом:

    write(pipefdc1a[1], stp1, evensize);
    write(pipefdc2a[1], stp2, oddsize);
    close(pipefdc1a[1]);
    close(pipefdc2a[1]);

должно выглядеть примерно так:

    write(pipefdc1a[1], stp1, evensize);
    write(pipefdc2a[1], stp2, oddsize);
    close(pipefdc1a[1]);
    close(pipefdc2a[1]);
    close(pipefdc1a[0]);  // Extra
    close(pipefdc2a[0]);  // Extra
    close(pipefdc1b[1]);  // Extra
    close(pipefdc2b[1]);  // Read all about it!

Я думаю, вам нужно смотреть на написание функций для выполнения работы, а не на весь код в main() программа, но вам все равно придется иметь дело с close() достаточно часто.

...