Qual é o objetivo do primeiro argumento para selecionar a chamada do sistema?

25

A partir de man select

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

nfds é o descritor de arquivo com o número mais alto em qualquer um dos três conjuntos, mais 1.

Qual é o objetivo nfds, quando já temos readfds, writefdse a exceptfdspartir da qual os descritores de arquivo podem ser determinados?

phunehehe
fonte
Eu estava prestes a perguntar sobre SO, mas é mais centralizado aqui, e as chamadas da API C são consideradas no tópico .
phunehehe

Respostas:

25

Em "Programação Avançada no Ambiente UNIX" , W. Richard Stevens diz que é uma otimização de desempenho:

Ao especificar o descritor mais alto em que estamos interessados, o kernel pode evitar passar por centenas de bits não utilizados nos três conjuntos de descritores, procurando por bits que estão ativados.

(1ª edição, página 399)

Se você estiver fazendo algum tipo de programação de sistemas UNIX, o manual do APUE é altamente recomendado.


ATUALIZAR

Um fd_seté geralmente capaz de rastrear até 1024 descritores de arquivos.

A maneira mais eficiente para controlar quais fdsestão definidas para 0e que são definidas como 1seria uma bitset, de modo que cada fd_setconsistiria de 1024 bits.

Em um sistema de 32 bits, um int longo (ou "palavra") é de 32 bits, o que significa que cada um fd_seté
1024/32 = 32 palavras.

Se nfdsfor algo pequeno, como 8 ou 16, o que seria em muitas aplicações, ele precisa apenas olhar dentro da 1ª palavra, que deve ser claramente mais rápida do que dentro de 32.

(Veja FD_SETSIZEe __NFDBITSde /usr/include/sys/select.hpara os valores em sua plataforma.)


ATUALIZAÇÃO 2

Por que a assinatura da função não é

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

Meu palpite é que, porque o código tenta manter todos os argumentos nos registros , para que a CPU possa trabalhar neles mais rapidamente e, se tivesse que rastrear duas variáveis ​​extras, a CPU talvez não tivesse registros suficientes.

Portanto, em outras palavras, selectestá expondo um detalhe de implementação para que seja mais rápido.

Mikel
fonte
2
Isso, ou o mais recente, The Linux Programming Interface
chris
O APUE também foi atualizado recentemente. Segunda edição: amazon.com/gp/aw/d.html/ref=aw_d_detail?pd=1&a=0201433079
Mikel
@chris Vou verificar a interface de programação do Linux. Obrigado.
Mikel
Obrigado pela informação, vou checar os livros quando tiver tempo.
phunehehe 21/02
APUE 2ª Ed: 27 Junho 2005 (tampas linux-2.4.22) TLPI: outubro de 2010 (tampas linux-2.6.35)
chris
6

Não tenho certeza, já que não sou um dos designers de select (), mas diria que é uma otimização de desempenho. A função de chamada sabe quantos descritores de arquivo ele coloca na leitura, gravação e exceto nos FDs; então, por que o kernel deve descobrir isso novamente?

Lembre-se de que no início dos anos 80, quando o select () foi introduzido, eles não tinham multi-gigaghertz, multi-processadores para trabalhar. Um VAX de 25 MHz foi bastante rápido. Além disso, você queria que o select () trabalhasse rapidamente, se pudesse: se alguma E / S estava aguardando o processo, por que esperar o processo?

Bruce Ediger
fonte
Para seu argumento, eu diria que precisamos nreadfds, nwritefdse nexceptfdsnão apenas um nfds.
phunehehe
Talvez seja para que nfdspossa entrar em um registro para acesso mais rápido. Se tivesse que rastrear três números, junto com todos os outros argumentos, talvez a CPU não tivesse registros suficientes. Obviamente, o kernel poderia ter criado seus próprios com nfdsbase em suas 3 variáveis ​​hipotéticas. Então, meu palpite é que está expondo um detalhe de implementação para obter eficiência.
Mikel
@ Mikel, phunehehe: nfdsArgumentos separados trariam muito pouco ganho. Na maioria das vezes, o processo abriu muito poucos processos em relação a FD_SETSIZE. Um caso típico pode ter (4,4,2) de 1024; fazer a verificação do kernel (4,4,4) é uma grande vitória sobre (1024,1024,1024), mas a otimização para (4,4,2) seria quase inútil.
Gilles 'SO- stop be evil'
@ Gilles: o ganho seria uma API mais limpa. (Como é, ou o programador tem de fazer o trabalho extra para calcular nfds, ou ser preguiçoso e chamada select(FD_SETSIZE, ...), o que seria mais lento.)
Mikel
OTOH, rastrear apenas uma variável máxima também pode ser mais fácil para o programador.
Mikel