Al ejecutar read normalmente, la función se bloquea a la espera de que llegue información por el file descriptor. Ésto puede ser evitado de dos maneras:
Abriendo el archivo (o lo que sea) pasando la opción
O_NONBLOCK en los flags. Por ejemplo:
fd=open("/dev/modem",O_RDONLY | O_NONBLOCK)
. Si el archivo
ya viene abierto, como es el caso de la standardinput o output, se puede
usar la función fcntl para modificar estos flags. Para este
caso, su uso sería este: fcntl(fd,F_SETFL,O_NONBLOCK)
.
(Hay que incluir fcntl.h).
Segunda y más potente forma de hacerlo: Usar select.
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
n
fd_set
timeval
Lo que hace select básicamente es esperar por la cantidad de tiempo indicada que haya un cambio en alguno de los file descriptors incluidos en los 3 sets. El primer set indica file descriptors a ser vigilados por entradas de datos (es el que nos interesa ahora). El segundo vigila que estén disponibles para escribir y el tercero.. bueno.. el tercero quién sabe para que sirve? =).
Si usabamos el método anterior para vigilar dos fuentes de entrada, estaríamos manejando las cosas "a la DOS". Estarímos ocupando tiempo del procesador en preguntar y preguntar y preguntar si hay algo nuevo.
Cuando se dice que una llama se bloquea quiere decir que el proceso se queda esperando algo sin ocupar absolutamente nada de tiempo del procesador.
Muchas situaciones son ideales para el uso de select. Por ejemplo una terminal de comunicaciones que debe vigilar el teclado y a la vez el modem puede hacerlo con select y de esta manera ser muy eficiente en el uso del procesador.
En la man page de select se encuentra la manera de crear y manipular los sets de file descriptors, y otros detalles importantes sobre esta función.
En las aplicaciones de consola que ofrecen una interfaz de modo texto a pantalla completa se suele usar la biblioteca curses, que ya tiene funciones para esperar teclas sin esperar.
Volver al índice.