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」を印刷する必要がある行は実行されません。したがって、実行がfgetc()

また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

関連情報