不写入文件描述符,如何使select()函数失效?

4
我在我的应用程序中有一个线程,用于监视一组客户端套接字。我使用select()来阻塞,直到客户端发出请求,以便我可以在不增加线程数的情况下高效地处理它。
现在问题是,当我将新客户端添加到客户端列表中时,我必须等待select()的超时时间(设置为10秒),才能将新套接字添加到被监听的套接字列表中。
所以我希望在超时之前让select()立即响应,以便可以立即监听客户端。
我已经有了解决方案:创建一个虚拟的socketpair,始终将其包含在我的被监听套接字列表中,并向其中写入以使select()立即响应,但我希望有更好的解决方案。
编辑: 由于我使用的GLibc太旧(并且我无法更新它),因此我无法访问eventfd()。所以我可能要使用fifo或socket。
你知道任何吗?
谢谢!

你可以使用 pthread_kill 或类似的方法杀死线程,然后重新启动它。 - jswolf19
那样做有点...过头了,不是吗? - Gui13
4个回答

7
通常唤醒选择循环的方式是将pipe() fd对的读端添加到选择监视集中。当您需要唤醒选择循环时,请向文件描述符的写端写入一些虚拟数据。
请注意,在Linux上,您可能还想考虑使用eventfd()而不是pipe() - 这可能会更有效率(尽管不太便携)。
您还可以在选择循环中处理监听套接字,而不是将其移交给另一个线程-这将在新客户端到来时隐式唤醒选择循环。

"eventfd()"正是我所需要的!由于我专注于Linux,它非常完美。谢谢! - Gui13
好的,关于这个更新:我没有最新的GLibc来支持eventfd(),所以我必须退而使用fifo或socket。但是,使用fifo的问题在于所有的open()/close()和文件系统操作,我想避免这些。有什么快速的方法可以解决这个问题吗? - Gui13
你有读过 fifo() 的手册吗?它没有涉及到文件系统访问 - 它只是提供了一对准备好的文件描述符。需要注意的一件事是,如果你将要执行其他程序,那么使用 fcntl() 来设置 FD_CLOEXEC - bdonlan
是的,我这么做的原因是fifo在程序崩溃或重启时会留在文件系统中,所以我宁愿使用socketpair()生成两个未命名的连接套接字,并将其设置为非阻塞。这样我就可以像使用fifo一样使用它们,而不必担心清理工作。你觉得有什么问题吗? - Gui13
糟糕,我的系统调用搞混了 - 我的意思是 pipe()! - bdonlan
显示剩余2条评论

3
您可以使用相同的select()调用来等待传入连接,方法是将监听套接字包含在FD集中;这样,当它指示有一个连接正在等待时,您可以在不阻塞的情况下接受连接并将新文件描述符添加到集合中。

是的,一开始我也是这么想的,但问题是,我的主监听套接字已经在应用程序的另一个部分中的select()中使用了(监听套接字可以用于除添加客户端之外的其他事情),所以你的解决方案在我的情况下是不切实际的。 - Gui13

0

你可以通过发送信号来强制从select()中返回EINTR,但在多线程程序中进行信号处理是黑魔法,而socketpair()更简单、更可靠。


多线程程序中使用信号仅仅为了唤醒选择循环?比它本身需要的要复杂得多... 甚至,人们会从信号处理程序中使用FIFO唤醒模式,专门是为了避免处理信号。不要反其道而行之。 - bdonlan
这正是我所说的:你可以,但你不应该。 - blaze

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接