Quel est le but du premier argument pour sélectionner l'appel système?

25

De man select

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

nfds est le descripteur de fichier le plus numéroté dans l'un des trois ensembles, plus 1.

À quoi sert nfds, lorsque nous en avons déjà readfds, writefdset à exceptfdspartir duquel les descripteurs de fichiers peuvent être déterminés?

phunehehe
la source
J'étais sur le point de demander sur SO, mais c'est plus centralisé ici, et les appels à l'API C sont considérés comme sur le sujet .
phunehehe

Réponses:

25

Dans "Programmation avancée dans l'environnement UNIX" , W. Richard Stevens dit qu'il s'agit d'une optimisation des performances:

En spécifiant le descripteur le plus élevé qui nous intéresse, le noyau peut éviter de parcourir des centaines de bits inutilisés dans les trois ensembles de descripteurs, en recherchant les bits qui sont activés.

(1ère édition, page 399)

Si vous faites n'importe quel type de programmation de systèmes UNIX, le livre APUE est fortement recommandé.


MISE À JOUR

An fd_setest généralement capable de suivre jusqu'à 1024 descripteurs de fichiers.

Le moyen le plus efficace de suivre ceux qui fdssont définis 0et ceux qui sont définis 1serait un jeu de bits, donc chacun fd_setserait composé de 1024 bits.

Sur un système 32 bits, un entier long (ou "mot") est de 32 bits, ce qui signifie que chacun fd_setest
1024/32 = 32 mots.

S'il nfdss'agit de quelque chose de petit, comme 8 ou 16, qu'il serait dans de nombreuses applications, il suffit de regarder à l'intérieur du premier mot, qui devrait clairement être plus rapide que de regarder à l'intérieur des 32.

(Voir FD_SETSIZEet à __NFDBITSpartir /usr/include/sys/select.hdes valeurs sur votre plate-forme.)


MISE À JOUR 2

Quant à savoir pourquoi la signature de fonction n'est pas

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

Je suppose que c'est parce que le code essaie de conserver tous les arguments dans les registres , de sorte que le processeur peut travailler plus rapidement sur eux, et s'il devait suivre 2 variables supplémentaires, le processeur pourrait ne pas avoir suffisamment de registres.

En d'autres termes, selectexpose un détail d'implémentation afin qu'il puisse être plus rapide.

Mikel
la source
2
Ça, ou la plus récente The Linux Programming Interface
chris
APUE a également été mis à jour récemment. Deuxième édition: amazon.com/gp/aw/d.html/ref=aw_d_detail?pd=1&a=0201433079
Mikel
@chris Je vérifierai l'interface de programmation Linux. Merci.
Mikel
Merci pour l'info, je vérifierai les livres quand j'aurai du temps.
phunehehe
APUE 2nd Ed: 27 juin 2005 (couvre linux-2.4.22) TLPI: octobre 2010 (couvre linux-2.6.35)
chris
6

Je ne suis pas sûr, car je ne suis pas l'un des concepteurs de select (), mais je dirais que c'est une optimisation des performances. La fonction appelante sait combien de descripteurs de fichiers elle a mis dans les FD en lecture, en écriture et à l'exception, alors pourquoi le noyau devrait-il le retrouver?

Rappelez-vous qu'au début des années 80, lorsque select () a été introduit, ils n'avaient pas de multi-gigaghertz, multi-processeurs avec lesquels travailler. Un VAX à 25 MHz était assez rapide. De plus, vous vouliez que select () fonctionne rapidement s'il le pouvait: si des E / S attendaient le processus, pourquoi le faire attendre?

Bruce Ediger
la source
Pour votre argument, je dirais que nous avons besoin nreadfds, nwritefdset nexceptfdsau lieu d'un seul nfds.
phunehehe
Peut-être que c'est pour nfdspouvoir aller dans un registre pour un accès plus rapide. S'il devait suivre trois nombres, ainsi que tous les autres arguments, le processeur n'aurait peut-être pas suffisamment de registres. Bien sûr, le noyau aurait pu créer le sien en nfdsfonction de vos 3 variables hypothétiques. Donc, je suppose qu'il expose un détail d'implémentation pour gagner en efficacité.
Mikel
@Mikel, phunehehe: Des nfdsarguments séparés apporteraient très peu de gain. La plupart du temps, le processus a ouvert très peu de processus par rapport à FD_SETSIZE. Un cas typique pourrait avoir (4,4,2) sur 1024; effectuer la vérification du noyau (4,4,4) est une grosse victoire (1024,1024,1024), mais l'optimisation jusqu'à (4,4,2) serait presque inutile.
Gilles 'SO- arrête d'être méchant'
@Gilles: le gain serait une API plus propre. (En l'état, le programmeur doit faire le travail supplémentaire pour calculer nfds, ou être paresseux et appeler select(FD_SETSIZE, ...), ce qui serait plus lent.)
Mikel
OTOH, le suivi d'une seule variable max pourrait également être plus facile pour le programmeur.
Mikel