使用如此多CPU功率的select()有什么问题?

时间:2013-11-02 02:21:16

标签: sockets tcp posix-select

我正在使用非阻塞套接字(C / C ++)和select编写网络通信程序。该程序非常大,所以我无法上传源代码。在非常激进的测试会话中,我使用测试代码频繁地打开和关闭TCP和UDP。总是最终一端没有响应并且CPU使用率超过98或99%。然后我使用 gdb 来附加。 “bt”显示以下内容:

0x00007f1b71b59ac3 in __select_nocancel () at ../sysdeps/unix/syscall-template.S:82
82  ../sysdeps/unix/syscall-template.S: No such file or directory.
    in ../sysdeps/unix/syscall-template.S

它可能是什么类型的错误?

$ uname -a
Linux kiosk2 2.6.32-34-generic #77-Ubuntu SMP Tue Sep 13 19:39:17 UTC 2011 x86_64 GNU/Linux

1 个答案:

答案 0 :(得分:33)

没有看代码就不可能说,但是当基于选择的循环开始以~100%的CPU使用率开始旋转时,这是因为你告诉select()要看的一个或多个套接字是准备好的 - for-read(和/或ready-for-write),以便select()立即返回而不是阻塞...但是代码忽略了实际recv()(或send())任何该套接字上的数据。在无法读取/写入任何内容之后,您的事件循环将通过再次调用select()来尝试返回休眠状态,但当然套接字的数据(或缓冲区空间,在准备写入的情况下)仍然存在等待处理,所以select()再次立即返回,错误的代码忽略了再次读取(或write()),并且我们周围的速度最快:)

另一种可能性是你将超时值传递给select(),该值为零或接近于零,导致select()即使没有任何套接字准备就绪也能很快返回...当人们忘记在每次调用select()之前重新初始化timeval结构时,通常会发生这种情况。您需要每次重新初始化timeval结构,因为select()的某些实现会在返回之前修改它。

我的建议是在调用select()之前和之后立即放置一些printf(或您最喜欢的等效物),并在重现故障时观察该输出。这将显示旋转是否发生在对select()的单次调用中,或者是否某些事件导致select()一次又一次地返回。