尝试对 fdopen() 函数返回的文件流使用 fgetc() 时程序执行挂起

尝试对 fdopen() 函数返回的文件流使用 fgetc() 时程序执行挂起

我正在编写一个程序,在其中创建 3 组 fifo(命名管道)来通过进程进行通信,我发现执行挂起的位置,但不知道原因,现在我陷入困境。

我发现使用时执行挂起fgetc()。传递给的文件流fgetc() 是函数返回的FILE* fdopen() 。这是失败的功能,样品1:

void mapear(int numProceso, int col, int val, char *signo)
{
  int ncol=0, fdSplit, fdBuf;
  char nombrePipe[10], cadenaLlave[10000], cadenaValor[10000], caracter;
  bool encontroCadena = false, yaEscribioValores = false, creado = false;
  FILE *ptrLectura, *ptrEscritura;

  sprintf(nombrePipe, "split%d", numProceso);
  fdSplit = open(nombrePipe, O_RDWR);
  if(fdSplit == -1)
    printf("\n[ERROR]-No se pudo abrir el pipe split, se volvera a tratar despues.\n");
  ptrLectura = fdopen(fdSplit, "r+");

  sprintf(nombrePipe, "buf%d", numProceso);
  fdBuf = open(nombrePipe, O_RDWR);
  if(fdBuf == -1)
    printf("\n[ERROR]-No se pudo abrir el pipe buf, se volvera a tratar despues.\n");

  while((caracter = fgetc(ptrLectura)) != EOF)
  {
    printf("REPITIENDO\n"); //DEBUG LINE 3: [NOT PRINTING ANYTHING] SHOWS THAT THE EXECUTION HANGS AFTER THE fgetc() CALL

    /*Print something to fdBuf pipe*/
  }
  fclose(ptrLectura);
  close(fdSplit);
  close(fdBuf);
}

应该打印“REPITIENDO”的行没有被执行......所以执行甚至没有进入 while,因为它挂在fgetc().

我还发布了我使用 . 创建 fifo 的示例mkfifo()mapear()PS:这些是每次被调用时打开的相同 fifo 样本2:

////////----CREATING THE FIRST SET OF PIPES AND OPENING THEM TO WRITE SOME REGISTERS TO EACH ONE----///////////
    mode_t fifo_mode = S_IRUSR | S_IWUSR;

    sprintf(nombrePipe, "split%d", cuentaArchivo);
    if(mkfifo(nombrePipe, fifo_mode) == -1)
      return -1;
  
      fd = open(nombrePipe, O_RDWR); 
      if(fd == -1)
        printf("\n[ERROR]-No se pudo abrir el pipe split, se volvera a tratar despues.\n");

    while (fgets(registro, sizeof registro, ptrLectura) != NULL) 
    {
      //IF THE DESIRED NUMBER OF REGISTERS PER PIPE IS REACHED THEN CLOSE THE CURRENT PIPE AND OPEN THE NEXT ONE
      if(cuentaRegistro == lineasPorArchivo) 
      {
        close(fd); 
        printf("Cerrando pipe %s\n", nombrePipe);//DEBUG LINE 1: SHOWS THAT THE N PIPE IS BEING CLOSED
        cuentaRegistro = 0;
        cuentaArchivo++;
        tieneHuerfana = false; 

        sprintf(nombrePipe, "split%d", cuentaArchivo);
        if(mkfifo(nombrePipe, fifo_mode) == -1)
          return -1;

        fd = open(nombrePipe, O_RDWR);
        if(fd == -1)
          printf("\n[ERROR]-No se pudo abrir el pipe split, se volvera a tratar despues.\n");                 
      }
      //WRITES REGISTER TO THE PIPE
      dprintf(fd,"%s", registro);
      cuentaRegistro++;
    }
    fclose(ptrLectura);
    close(fd);
    printf("Cerrando pipe %s\n", nombrePipe); //DEBUG LINE 2: SHOWS THAT THE LAST PIPE IS BEING CLOSED

    ////////----JUST CREATING THE SECOND SET OF PIPES----///////////
    for(i = 1; i <= nmappers; i++)
    {
      sprintf(nombrePipe, "buf%d", i);
      if(mkfifo(nombrePipe, fifo_mode) == -1)
        return -1;      
    }

    ////////----JUST CREATING THE THIRD SET OF PIPES----///////////
    for(i = 1; i <= nreducers; i++)
    {
      sprintf(nombrePipe, "output%d", i);
      if(mkfifo(nombrePipe, fifo_mode) == -1)
        return -1;      
    }

我还将提供调用该函数的示例void mapear(int numProceso, int col, int val, char *signo) 样本3:

////////----CREATING THE CHILD PROCESSES THAT ARE GOING TO CALL mapear()----///////////

    pid_t mappers_pids[nmappers], reducers_pids[nreducers];

    for(i = 1; i <= nmappers; i++)
    {
      if((pid = fork()) == 0)
      {
        signal(SIGCONT, handle_sigcont);
        signal(SIGUSR1, handle_sigusr1);
        pause();
        mapear(i, col, val, signo); 
        kill(getppid, SIGCONT);
      }
      else if(pid < 0)
      {
        return -1;
      }
      //Padre
      mappers_pids[i] = pid;
    }

最后,我将给出父进程向其子​​进程发送信号的示例,以便他们可以调用mapear() 样本4:

              ////////----FATHER SENDING SIGNALS TO IT'S CHILDS PROCESSES, SO THEY CAN CALL mapear()----///////////
              for(i = 1; i <= nmappers; i++)
              {
                kill(mappers_pids[i], SIGCONT);
                pause();
              }

在最后一个示例中,除了父进程向其子​​进程发送信号之外,父进程还会等待,pause() 直到收到来自当前正在执行mapear() 函数的子进程的信号。

**PS:执行顺序是:

-样本2

-样本3

-样本4

-SAMPLE1(我认为问题出在哪里)**

非常感谢,我真的希望有人能提供帮助!

更新:我被告知要发布一个可重现的示例,所以这里是:

int main(int argc, char *argv[])
{
  int i, pid, col, val, lineas, nmappers, nreducers, intermedios, lineasPorArchivo, lineasHuerfanas, bufsPorProceso, bufsHuerfanos, cuentaBuf = 1, fd;
  int cuentaArchivo=1, cuentaRegistro=0;
  bool salir = false, tieneHuerfana = false;
  char *consulta = (char*) malloc(10);
  char *signo = (char*) malloc(2); 
  FILE *ptrLectura, *ptrEscritura;
  char registro[150], nombrePipe[10];

    lineas = 16;
    nmappers = 4;
    nreducers = 2;
    intermedios = 0;

    lineasPorArchivo = lineas/nmappers;
    lineasHuerfanas = lineas%nmappers;

    ptrLectura = fopen("log16","r");

    ////////----CREATING THE FIRST SET OF PIPES AND OPENING THEM TO WRITE SOME REGISTERS TO EACH ONE----///////////
    mode_t fifo_mode = S_IRUSR | S_IWUSR;

    sprintf(nombrePipe, "split%d", cuentaArchivo);
    if(mkfifo(nombrePipe, fifo_mode) == -1)
      return -1;
  
      fd = open(nombrePipe, O_RDWR); 
      if(fd == -1)
        printf("\n[ERROR]-No se pudo abrir el pipe split, se volvera a tratar despues.\n");

    while (fgets(registro, sizeof registro, ptrLectura) != NULL) 
    {
      //IF THE DESIRED NUMBER OF REGISTERS PER PIPE IS REACHED THEN CLOSE THE CURRENT PIPE AND OPEN THE NEXT ONE
      if(cuentaRegistro == lineasPorArchivo) 
      {
        close(fd); 
        printf("Cerrando pipe %s\n", nombrePipe);//DEBUG LINE 1: SHOWS THAT THE N PIPE IS BEING CLOSED
        cuentaRegistro = 0;
        cuentaArchivo++;
        tieneHuerfana = false; 

        sprintf(nombrePipe, "split%d", cuentaArchivo);
        if(mkfifo(nombrePipe, fifo_mode) == -1)
          return -1;

        fd = open(nombrePipe, O_RDWR);
        if(fd == -1)
          printf("\n[ERROR]-No se pudo abrir el pipe split, se volvera a tratar despues.\n");                 
      }
      //WRITES REGISTER TO THE PIPE
      dprintf(fd,"%s\n", registro);
      cuentaRegistro++;
    }
    fclose(ptrLectura);
    close(fd);
    printf("Cerrando pipe %s\n", nombrePipe); //DEBUG LINE 2: SHOWS THAT THE LAST PIPE IS BEING CLOSED

    ////////----JUST CREATING THE SECOND SET OF PIPES----///////////
    for(i = 1; i <= nmappers; i++)
    {
      sprintf(nombrePipe, "buf%d", i);
      if(mkfifo(nombrePipe, fifo_mode) == -1)
        return -1;      
    }

    ////////----CREATING THE CHILD PROCESSES THAT ARE GOING TO CALL mapear()----///////////

    pid_t mappers_pids[nmappers], reducers_pids[nreducers];

    for(i = 1; i <= nmappers; i++)
    {
      if((pid = fork()) == 0)
      {
        signal(SIGCONT, handle_sigcont);
        signal(SIGUSR1, handle_sigusr1);
        pause();
        mapear(i, col, val, signo); 
        kill(getppid, SIGCONT);
      }
      else if(pid < 0)
      {
        return -1;
      }
      //Padre
      mappers_pids[i] = pid;
    }
    
    sprintf(consulta, "4,=,0");

    if(validarConsulta(consulta, &col, &val, &signo))
    {
      printf("\n[EN PROCESO]-Buscando registros de la columna %d que sean %s %d\n", col, signo, val);

      ////////----FATHER SENDING SIGNALS TO IT'S CHILDS PROCESSES, SO THEY CAN CALL mapear()----///////////
      for(i = 1; i <= nmappers; i++)
      {
        kill(mappers_pids[i], SIGCONT);
        pause();
      }

      printf("SUCCES!\n"); //EXECUTION SHOULD REACH THIS POINT WITHOUT HANGING 
    }
  return 0;
}

bool validarConsulta(char *consulta, int *col, int *val, char **signo)
{
  char *columna, *simbolo, *valor;

  columna = strtok(consulta, ",");
  *signo = strtok(NULL,",");
  valor = strtok(NULL,",");
  *col = atoi(columna);
  *val = atoi(valor);

  return (strcmp(*signo,"<") == 0 || strcmp(*signo,"<=") == 0  || strcmp(*signo,">") == 0 || strcmp(*signo,">=") == 0 || strcmp(*signo,"=") == 0);
}

void mapear(int numProceso, int col, int val, char *signo)
{
  int fdSplit, fdBuf, cont = 0;
  char nombrePipe[10], caracter;
  FILE *ptrLectura, *ptrEscritura;

  sprintf(nombrePipe, "split%d", numProceso);
  fdSplit = open(nombrePipe, O_RDWR);
  if(fdSplit == -1)
    printf("\n[ERROR]-No se pudo abrir el pipe split, se volvera a tratar despues.\n");
  ptrLectura = fdopen(fdSplit, "r+");

  sprintf(nombrePipe, "buf%d", numProceso);
  fdBuf = open(nombrePipe, O_RDWR);
  if(fdBuf == -1)
    printf("\n[ERROR]-No se pudo abrir el pipe buf, se volvera a tratar despues.\n");

  printf("STUCK JUST BEFORE THE WHILE\n");
  while((caracter = fgetc(ptrLectura)) != EOF)
  {
    printf("REPEATING %d\n", cont); //DEBUG LINE 3: [NOT PRINTING ANYTHING] SHOWS THAT THE EXECUTION HANGS AFTER THE fgetc() CALL
    cont++;
    /*Print something to fdBuf pipe*/
  }
  fclose(ptrLectura);
  close(fdSplit);
  close(fdBuf);
}

void handle_sigusr1(int sig)
{
  printf("\nˑMapper con PID[%d] culmina.\n", getpid());
  exit(0);
}

void handle_sigusr2(int sig)
{
  printf("\nˑReducer con PID[%d] culmina.\n", getpid());
  exit(0);
}

void handle_sigcont(int sig){
}

现在执行甚至还没有到达 mapear() 函数调用。执行仍然挂起,但现在在向子进程发送信号 SIGCONT 时挂起。

PD:为了使示例正常工作,您必须在保存示例代码的同一文件夹中找到一个名为“log16”的文件。该文件应如下所示:

   1        0     65 2592042    1     -1 1009884   -1     -1    -1  0   1  -1  -1  2  9 -1 -1
    2        0     71 2592046    1     -1 1010132   -1     -1    -1  0   1  -1  -1  2  9 -1 -1
    3       19     41 1893368    1     -1 1010108   -1     -1    -1  0   1  -1  -1  2  9 -1 -1
    4       19     42 1825976    1     -1  2172   -1     -1    -1  0   1  -1  -1  2  9 -1 -1
    5   516420     15 2592030    2     -1  4940   -1     -1    -1  0   2  -1  -1  1  8 -1 -1
    6  1284365     26 2012962    1     -1 14088   -1     -1    -1  1   3  -1  -1  1  8 -1 -1
    7  1284365     26 2290213    1     -1 13556   -1     -1    -1  1   3  -1  -1  1  8 -1 -1
    8  1284365     28 2058925    1     -1 14124   -1     -1    -1  1   3  -1  -1  1  8 -1 -1
    9  1284366     26 1782465    1     -1 14584   -1     -1    -1  1   3  -1  -1  1  8 -1 -1
   10  1284366     27 1831699    1     -1 14112   -1     -1    -1  1   3  -1  -1  1  8 -1 -1
   11  1389267    351 1573008    1     -1 351604   -1     -1    -1  0   4  -1  -1  1  8 -1 -1
   12  1389297    332 1572997    1     -1 351028   -1     -1    -1  0   4  -1  -1  1  8 -1 -1
   13  1477792      6 1484828    1     -1 351504   -1     -1    -1  0   4  -1  -1  1  8 -1 -1
   14  1480061     23 1482543    1     -1 352136   -1     -1    -1  0   4  -1  -1  1  8 -1 -1
   15  1666234     26 312610    1     -1 1690068   -1     -1    -1  0   5  -1  -1  2 11 -1 -1
   16  1669900      9 262547    1     -1 1558900   -1     -1    -1  0   5  -1  -1  2 11 -1 -1

相关内容