¿Cuál es el propósito del primer argumento para seleccionar la llamada al sistema?


25

Desde man select

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

nfds es el descriptor de archivo con el número más alto en cualquiera de los tres conjuntos, más 1.

¿Cuál es el propósito nfds, cuando ya lo tenemos readfds, writefdsy exceptfdsde qué se pueden determinar los descriptores de archivos?


Estaba a punto de preguntar sobre SO, pero aquí está más centralizado, y las llamadas de API C se consideran sobre el tema .
phunehehe

Respuestas:


25

En "Programación avanzada en el entorno UNIX" , W. Richard Stevens dice que es una optimización del rendimiento:

Al especificar el descriptor más alto en el que estamos interesados, el núcleo puede evitar pasar por cientos de bits no utilizados en los tres conjuntos de descriptores, buscando bits que estén activados.

(1a edición, página 399)

Si está haciendo algún tipo de programación de sistemas UNIX, el libro APUE es muy recomendable.


ACTUALIZAR

Un fd_setgeneralmente puede rastrear hasta 1024 descriptores de archivo.

La forma más eficiente de rastrear cuáles fdsestán configurados 0y cuáles están configurados 1sería un conjunto de bits, por lo que cada uno fd_setconsistiría en 1024 bits.

En un sistema de 32 bits, un int largo (o "palabra") es de 32 bits, lo que significa que cada uno fd_setes
1024/32 = 32 palabras.

Si nfdses algo pequeño, como 8 o 16, que sería en muchas aplicaciones, solo necesita mirar dentro de la primera palabra, que claramente debería ser más rápido que mirar dentro de los 32.

(Consulte FD_SETSIZEy __NFDBITSdesde /usr/include/sys/select.hlos valores de su plataforma).


ACTUALIZACIÓN 2

En cuanto a por qué la firma de la función no es

int select(fd_set *readfds, int nreadfds,
           fd_set *writefds, int nwritefds,
           fd_set *exceptfds, int nexceptfds,
           struct timeval *timeout);

Supongo que es porque el código intenta mantener todos los argumentos en los registros , por lo que la CPU puede trabajar en ellos más rápido, y si tuviera que rastrear 2 variables adicionales, la CPU podría no tener suficientes registros.

En otras palabras, selectestá exponiendo un detalle de implementación para que pueda ser más rápido.


2
Eso, o la más reciente Interfaz de programación de Linux
chris

APUE se actualizó recientemente también. Segunda edición: amazon.com/gp/aw/d.html/ref=aw_d_detail?pd=1&a=0201433079
Mikel

@chris Comprobaré la interfaz de programación de Linux. Gracias.
Mikel

Gracias por la información, revisaré los libros cuando tenga tiempo.
phunehehe

APUE 2nd Ed: 27 de junio de 2005 (cubre linux-2.4.22) TLPI: octubre de 2010 (cubre linux-2.6.35)
chris

6

No estoy seguro, ya que no soy uno de los diseñadores de select (), pero diría que es una optimización del rendimiento. La función de llamada sabe cuántos descriptores de archivo pone en lectura, escritura y excepto FD, entonces, ¿por qué el núcleo debería resolverlo nuevamente?

Recuerde que a principios de los años 80, cuando se introdujo select (), no tenían multi-gigaghercios, multiprocesadores para trabajar. Un VAX de 25 MHz fue bastante rápido. Además, quería que select () funcionara rápido si pudiera: si alguna E / S estaba esperando el proceso, ¿por qué hacer que el proceso espere?


A su argumento, diría que necesitamos nreadfds, nwritefdsy en nexceptfdslugar de solo uno nfds.
phunehehe

Tal vez sea para que nfdspueda ingresar en un registro para un acceso más rápido. Si tuviera que rastrear tres números, junto con todos los demás argumentos, tal vez la CPU no tendría suficientes registros. Por supuesto, el núcleo podría haber creado uno propio nfdsbasado en sus 3 variables hipotéticas. Entonces, supongo que está exponiendo un detalle de implementación para ganar eficiencia.
Mikel

@Mikel, phunehehe: nfdsargumentos separados traerían muy poca ganancia. La mayoría de las veces, el proceso ha abierto muy pocos procesos en relación con FD_SETSIZE. Un caso típico podría tener (4,4,2) de 1024; hacer la verificación del kernel (4,4,4) es una gran victoria sobre (1024,1024,1024), pero la optimización hasta (4,4,2) sería casi inútil.
Gilles 'SO- deja de ser malvado'

@Gilles: la ganancia sería una API más limpia. (Tal como están las cosas, o bien el programador tiene que hacer el trabajo extra para calcular nfds, o ser flojo y llamar select(FD_SETSIZE, ...), lo que sería más lento).
Mikel

OTOH, rastrear solo una variable máxima también podría ser más fácil para el programador.
Mikel
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.