Wozu dient das erste Argument zur Auswahl des Systemaufrufs?

25

Von man select

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

nfds ist der Dateideskriptor mit der höchsten Nummer in einem der drei Sätze plus 1.

Wofür nfdshaben wir, wenn schon readfds, writefdsund exceptfdsworaus können die Dateideskriptoren ermittelt werden?

phunehehe
quelle
Ich wollte gerade nach SO fragen, aber es ist hier zentraler, und C-API-Aufrufe werden als thematisch betrachtet .
Phunehehe

Antworten:

25

In "Advanced Programming in the UNIX Environment" beschreibt W. Richard Stevens dies als eine Leistungsoptimierung:

Durch die Angabe des höchsten Deskriptors, an dem wir interessiert sind, kann der Kernel vermeiden, Hunderte nicht verwendeter Bits in den drei Deskriptorsätzen zu durchlaufen und nach aktivierten Bits zu suchen.

(1. Auflage, Seite 399)

Wenn Sie UNIX-Systeme programmieren, wird das APUE-Buch dringend empfohlen.


AKTUALISIEREN

In der fd_setRegel können bis zu 1024 Dateideskriptoren verfolgt werden.

Der effizienteste Weg zu verfolgen, auf welchen fdseingestellt ist 0und auf welche eingestellt ist, 1wäre ein Bitsatz, also fd_setwürde jeder aus 1024 Bits bestehen.

Auf einem 32-Bit - System, ein long int (oder "Wort") beträgt 32 Bits, so dass jeder daß Mittel fd_setist
1024/32 = 32 Worte.

Wenn nfdses sich bei etwas Kleinem wie 8 oder 16 handelt, wie es in vielen Anwendungen der Fall ist, muss nur das erste Wort gesucht werden, was eindeutig schneller sein sollte als alle 32.

(Siehe FD_SETSIZEund __NFDBITSvon /usr/include/sys/select.hfür die Werte auf Ihrer Plattform.)


UPDATE 2

Warum ist die Funktionssignatur nicht

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

Ich vermute, es liegt daran, dass der Code versucht, alle Argumente in Registern zu speichern , damit die CPU schneller mit ihnen arbeiten kann. Wenn zwei zusätzliche Variablen nachverfolgt werden müssten, verfügt die CPU möglicherweise nicht über genügend Register.

Mit anderen Worten, selectwird ein Implementierungsdetail verfügbar gemacht, damit es schneller sein kann.

Mikel
quelle
2
Das, oder die neuere Linux-Programmierschnittstelle
Chris
APUE wurde kürzlich ebenfalls aktualisiert. Zweite Ausgabe: amazon.com/gp/aw/d.html/ref=aw_d_detail?pd=1&a=0201433079
Mikel
@chris Ich werde die Linux-Programmierschnittstelle überprüfen. Vielen Dank.
Mikel
Vielen Dank für die Info, ich werde die Bücher überprüfen, wenn ich etwas Zeit habe.
Phunehehe
APUE 2nd Ed: 27. Juni 2005 (umfasst Linux-2.4.22) TLPI: Oktober 2010 (umfasst Linux-2.6.35)
Chris
6

Ich weiß es nicht genau, da ich nicht zu den Designern von select () gehöre, aber ich würde sagen, es ist eine Leistungsoptimierung. Die aufrufende Funktion weiß, wie viele Dateideskriptoren in die Lese-, Schreib- und Ausnahmen-FDs eingefügt wurden. Warum sollte der Kernel dies also erneut herausfinden?

Denken Sie daran, dass in den frühen 80er Jahren, als select () eingeführt wurde, keine Multi-Gigaghertz-Prozessoren zur Verfügung standen, mit denen gearbeitet werden konnte. Ein 25 MHz VAX war ziemlich schnell. Außerdem wollten Sie, dass select () schnell arbeitet, wenn dies möglich ist: Wenn einige E / A auf den Prozess warteten, warum sollte der Prozess warten?

Bruce Ediger
quelle
Um Ihr Argument würde ich sagen , wir brauchen nreadfds, nwritefdsund nexceptfdsstatt nur einem nfds.
Phunehehe
Vielleicht ist es so, dass nfdsman sich für einen schnelleren Zugriff registrieren kann. Wenn es drei Zahlen zusammen mit allen anderen Argumenten verfolgen müsste, hätte die CPU möglicherweise nicht genügend Register. Natürlich hätte der Kernel nfdsauf der Grundlage Ihrer hypothetischen 3 Variablen eine eigene erstellen können. Ich vermute also, dass ein Implementierungsdetail sichtbar gemacht wird, um die Effizienz zu steigern.
Mikel
@Mikel, phunehehe: Getrennte nfdsArgumente würden sehr wenig Gewinn bringen. In den meisten Fällen hat der Prozess nur sehr wenige Prozesse in Bezug auf geöffnet FD_SETSIZE. Ein typischer Fall könnte (4,4,2) von 1024 haben; Die Kernelüberprüfung (4,4,4) ist ein großer Gewinn gegenüber (1024,1024,1024), aber eine Optimierung auf (4,4,2) wäre nahezu nutzlos.
Gilles 'SO- hör auf böse zu sein'
@ Gilles: Der Gewinn wäre eine sauberere API. (Wie es ist, muss entweder der Programmierer die zusätzliche Arbeit machen, um zu berechnen nfds, oder er muss faul sein und anrufen select(FD_SETSIZE, ...), was langsamer wäre.)
Mikel
OTOH, das Verfolgen von nur einer maximalen Variablen könnte auch für den Programmierer einfacher sein.
Mikel