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()추신: 이는 호출될 때마다 열리는 동일한 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

관련 정보