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

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

man select

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

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

nfds当我们已经有了可以确定文件描述符的readfdswritefds和时,的目的是什么?exceptfds

答案1

《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);

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

换句话说,select就是公开实现细节,以便速度更快。

答案2

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

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

相关内容