select系统调用的第一个参数的目的是什么?

phu*_*ehe 25 system-calls file-descriptors

man select

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);
Run Code Online (Sandbox Code Playgroud)

nfds 是三个集合中任何一个中编号最大的文件描述符,加 1。

的目的是什么nfds,当我们已经有了readfds,writefdsexceptfds,从中可以确定文件描述符?

Mik*_*kel 27

“UNIX 环境中的高级编程”中,W. Richard Stevens 说这是一种性能优化:

通过指定我们感兴趣的最高描述符,内核可以避免遍历三个描述符集中的数百个未使用的位,寻找打开的位。

(第一版,第 399 页)

如果您正在从事任何类型的 UNIX 系统编程,强烈推荐 APUE 书籍。


更新

Anfd_set通常能够跟踪多达 1024 个文件描述符。

跟踪哪些fds设置为0和哪些设置为的最有效方法是位集1,因此每个fd_set将包含 1024 位。

在 32 位系统上,long int(或“字”)是 32 位,这意味着每个fd_set
1024 / 32 = 32 个字。

如果nfds是一些小的东西,例如 8 或 16,在许多应用程序中都是这样,它只需要查看第一个单词,这显然比查看所有 32 个单词要快。

(查看FD_SETSIZE__NFDBITS来自/usr/include/sys/select.h您平台上的值。)


更新 2

至于为什么函数签名不是

int select(fd_set *readfds, int nreadfds,
           fd_set *writefds, int nwritefds,
           fd_set *exceptfds, int nexceptfds,
           struct timeval *timeout);
Run Code Online (Sandbox Code Playgroud)

我的猜测是因为代码试图将所有参数保存在registers 中,因此 CPU 可以更快地处理它们,如果它必须跟踪额外的 2 个变量,则 CPU 可能没有足够的寄存器。

换句话说,select就是公开一个实现细节,以便它可以更快。

  • 那个,或者最近的 [Linux 编程接口](http://www.man7.org/tlpi) (2认同)

Bru*_*ger 6

我不确定,因为我不是 select() 的设计者之一,但我会说这是一种性能优化。调用函数知道它在 read、write 和 except FD 中放入了多少文件描述符,那么内核为什么要再次计算出来呢?

请记住,在 80 年代初,当 select() 被引入时,他们没有可使用的多千兆赫兹、多处理器。25 MHz VAX 速度相当快。另外,如果可以的话,您希望 select() 快速工作:如果某些 I/O 正在等待进程,为什么要让进程等待?