我一直在阅读libev 的源代码,偶然发现了这个评论:
a) epoll 默默地从 fd 集中删除 fds。因为没有任何东西告诉我们一个 fd 已经被移除,所以我们必须不断地“重新武装”我们怀疑可能已经改变的 fd(与 kqueue 相同的问题,但那里的成本要低得多)。
我一直在一些现代 linux 内核上使用 epoll(直接使用系统调用)进行一些测试,但我无法重现它。我没有看到“默默消失的 fds”有任何问题。有人可以详细说明一下并告诉我这是否仍然是一个问题?
我一直在阅读libev 的源代码,偶然发现了这个评论:
a) epoll 默默地从 fd 集中删除 fds。因为没有任何东西告诉我们一个 fd 已经被移除,所以我们必须不断地“重新武装”我们怀疑可能已经改变的 fd(与 kqueue 相同的问题,但那里的成本要低得多)。
我一直在一些现代 linux 内核上使用 epoll(直接使用系统调用)进行一些测试,但我无法重现它。我没有看到“默默消失的 fds”有任何问题。有人可以详细说明一下并告诉我这是否仍然是一个问题?
这是相当模糊的文本,但我想这只是如果描述符在close
其他地方是 d ,它会被默默地从集合中删除。来自 Linux 联机帮助页,epoll(7):
Q6 关闭一个文件描述符会导致它自动从所有 epoll 集中移除吗?
A6 可以,但请注意以下几点。文件描述符是对打开文件描述的引用(请参阅 参考资料
open(2)
)。每当通过dup(2)
、dup2(2)
、fcntl(2)
F_DUPFD
或复制描述符时fork(2)
,都会创建一个引用相同打开文件描述的新文件描述符。一个打开的文件描述会继续存在,直到所有引用它的文件描述符都已关闭。只有在引用底层打开文件描述的所有文件描述符都已关闭之后(或者在使用显式删除描述符之前,文件描述符才会从 epoll 集中删除)epoll_ctl(2)
EPOLL_CTL_DEL
)。这意味着即使在作为 epoll 集的一部分的文件描述符已经关闭之后,如果引用相同底层文件描述的其他文件描述符仍然打开,则可能会报告该文件描述符的事件。
所以你有一个 fd 42 的套接字。它得到close
d,然后从epoll
对象中删除。但是内核不会libev
通过. epoll_wait
现在epoll_modify
再次使用 fd = 调用42
。epoll_modify
不知道这个文件描述符 42 是否与epoll
对象中已经存在的相同,或者文件描述符编号为 42 的其他文件描述是否被重用。
人们也可能会争辩说,这些评论只是在咆哮,而libev
API 的设计在这里有问题。