Haciendo stdin sin locking

Tengo un ejercicio en el que debo imprimir un archivo lentamente (intervalos de 1 segundo) hasta que el archivo finalice, a menos que el usuario escriba un carácter.

Hasta ahora, el progtwig genera el archivo en intervalos de un segundo, lo que es genial, pero cuando escribo un carácter, no sucede nada. Mi conjetura es que estoy utilizando seleccionar mal de alguna manera.

Este es el progtwig final que terminé enviando.

#include  #include  #include  #include  #include  #include  int main(void) { FILE* infile; char str[100]; fd_set readset; struct timeval tv; // open a file if((infile = fopen("infile", "r")) == NULL) { (void)printf("Couldn't open the file\n"); exit(1); } // file was opened successfully else { // while we are not at the end of a file while(fgets(str, 100, infile) != NULL) { FD_ZERO(&readset); FD_SET(fileno(stdin), &readset); // set the time value to 1 second tv.tv_sec = 1; tv.tv_usec = 0; select(fileno(infile)+1, &readset, NULL, NULL, &tv); // the user typed a character so exit if(FD_ISSET(fileno(stdin), &readset)) { fclose(infile); exit(0); } // the user didn't type a character so print the next line else { fgets(str, 100, stdin); puts(str); } } // clean up fclose(infile); } // report success return 0; } 

¡Gracias por la ayuda!

Esta es una versión de trabajo, usando tcgetattr / tcsetattr:

 #include  #include  #include  #include  #include  #include  #include  #include  int main(void) { FILE* infile; char str[100]; fd_set readset; struct timeval tv; struct termios ttystate, ttysave; // open a file if((infile = fopen("infile", "r")) == NULL) { (void)printf("Couldn't open the file\n"); exit(1); } // file was opened successfully //get the terminal state tcgetattr(STDIN_FILENO, &ttystate); ttysave = ttystate; //turn off canonical mode and echo ttystate.c_lflag &= ~(ICANON | ECHO); //minimum of number input read. ttystate.c_cc[VMIN] = 1; //set the terminal attributes. tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); // while we are not at the end of a file while(fgets (str, 100, infile)) { // set the time value to 1 second tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&readset); FD_SET(fileno(stdin), &readset); select(fileno(stdin)+1, &readset, NULL, NULL, &tv); // the user typed a character so exit if(FD_ISSET(fileno(stdin), &readset)) { fgetc (stdin); // discard character break; } // the user didn't type a character so print the next line else { puts(str); // not needed: sleep(1); } } // clean up fclose(infile); ttystate.c_lflag |= ICANON | ECHO; //set the terminal attributes. tcsetattr(STDIN_FILENO, TCSANOW, &ttysave); // report success return 0; } 

El sleep(1); ya no es necesario

El terminal está búfer de líneas. No envía texto al progtwig hasta que presione la tecla Intro . Puede haber una manera de deshabilitar el búfer de línea de terminal, pero me imagino que está fuera del scope de su asignación.

Se detiene cuando presionas Enter . Sin embargo, no se cierra de inmediato. Eso es algo que querrás arreglar. Deshazte de ese sleep(1) .

Ahora tu progtwig de spams de texto! Dio select un tiempo de espera de un segundo, ¿verdad?

 // set the time value to 1 second tv.tv_sec = 1; tv.tv_usec = 0; 

La razón por la que el tiempo de espera no se mantiene es porque la select está modificando el valor del tiempo de espera. De la página del manual :

En Linux, select () modifica el tiempo de espera para reflejar la cantidad de tiempo no dormido; La mayoría de las otras implementaciones no hacen esto. (POSIX.1-2001 permite cualquier comportamiento). Esto causa problemas cuando el código de Linux que lee el tiempo de espera se transfiere a otros sistemas operativos, y cuando el código se transporta a Linux que reutiliza una estructura de tiempo para varias selecciones () en un bucle sin reinicializándolo. Considere que el tiempo de espera no está definido después de que se devuelve select ().

Deberá inicializar el timeval antes de cada llamada para seleccionar, no solo una vez al comienzo del progtwig.

Usted querría hacer su progtwig multiproceso. Cree un hilo que imprima el archivo cada intervalo de 1 segundo, y su hilo principal recibiría una entrada de stdin, luego haga una señal al otro hilo para que deje de imprimir cada vez que reciba la entrada.

Parte de su problema es que está usando el modo de espera sleep(1) que hará que esa línea tarde un segundo completo en ejecutarse. Si el usuario escribe un carácter, tendrá que esperar hasta un segundo completo antes de que su progtwig responda. Así que incluso una vez que consiga que la parte no bloqueante funcione, seguirá teniendo problemas.

La solución es usar nanosleep o usleep para pausar el progtwig por menos de 1 segundo. Mi recomendación sería dormir durante 1/100 de segundo * usando una de esas funciones) y verificar si se presionan las teclas de usuario cada vez. En la centésima vez, imprima la siguiente parte del archivo. De esa manera, el archivo sigue a la velocidad correcta, pero el usuario puede detenerlo cuando lo desee y el progtwig responderá a su comando muy rápidamente.