Su tarea requiere un bucle de eventos basado en select
o epoll
. Un evento que esperaría es la entrada del usuario:cuando STDIN_FILENO
queda listo para leer. Otro es el temporizador periódico de 1 segundo cuando necesita sondear el controlador.
Hay bastantes bibliotecas que implementan un bucle de eventos para que pueda concentrarse en qué eventos necesita manejar y cómo. libevent
es uno de los más antiguos, rico en funciones y popular.
Creo que la forma "Unix" sería no solicitar la entrada del usuario, sino reaccionar a la señal del usuario. Por ejemplo, cuando el usuario presiona Ctrl-C, el proceso actualmente en ejecución recibe SIGINT.
Puede encontrar un ejemplo de cómo usar correctamente SIGINT para interrumpir un bucle aquí. Copiándolo en la respuesta en caso de que el enlace se vuelva obsoleto:
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static volatile sig_atomic_t got_signal = 0;
static void my_sig_handler(int signo)
{
got_signal = 1;
}
int main()
{
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = &my_sig_handler;
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("sigaction");
return EXIT_FAILURE;
}
for (;;) {
if (got_signal) {
got_signal = 0;
printf("Received interrupt signal!\n");
}
printf("Doing useful stuff...\n");
sleep(1); /* Sleep is not only useful, it is essential! */
}
return EXIT_SUCCESS;
}
(en tu caso sería buena idea poner break;
en el if
bloquear o usar while(!got_signal)
)
La respuesta simple es subprocesos múltiples, donde tiene un subproceso implementado para esperar la entrada del usuario, mientras el ciclo continúa. Así que ten esto:
char flag = 1;
while (flag) {
// run the loop
// if thing happens deploy the thread which will ask user for input
}
Hace tiempo que no hago hilos, creo que esta página sería mejor que yo tratando de explicártelo:https://randu.org/tutorials/threads/