在fork被卡在未知位置的读取循环中之后,从子管道中进行读取

时间:2018-12-13 14:58:15

标签: c pipe fork

我正在编写一个程序,在其中我进行了两次分叉以创建2个子进程,这些子进程通过其stdout将信息发送给父进程。孩子们启动该程序使其递归。发生的情况是,父级在读取子级时陷入了读取循环,但这不是永远的循环(存在有限且预期的输出)。它只是无法超越它。

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

我为孩子1和2尝试了2个不同的循环,因为在某个时候我发现这是问题所在,但不是。

我在某种程度上限制了对C的理解;如果您能回答并解释,那就太好了。

我正在尝试遵守“最低要求的代码”规则,但是如果您觉得需要其他条件,请询问,我将添加它们。

1 个答案:

答案 0 :(得分:0)

正如我在comment中所猜到的那样,您关闭的文件描述符不足-这次的问题出在父级,尽管通常是子进程没有完成足够的关闭。


经验法则:如果您 dup2() 管道的一端到标准输入或标准输出,同时关闭两个 由返回的原始文件描述符 pipe() 尽快地。 特别是,在使用任何 exec*() 系列功能。

如果您将描述符与任何一个重复,则该规则也适用 dup() 要么 fcntl()F_DUPFD


您通过4个pipe()调用创建了8个文件描述符。在孩子中,请根据经验法则将其关闭。

但是,在尝试从子级读取到EOF之前,您的父级仅关闭2个文件描述符。而且,由于它仍然具有从开放读取的管道的写端,因此它将永远不会得到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()。 / p>