select()使用过多CPU资源的问题是什么?

8

我正在使用非阻塞套接字(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

那么,问题出在哪里? - tshepang
1个回答

47

无法准确判断问题原因,需要查看代码。但通常情况下,当基于select的循环开始以~100% CPU使用率旋转时,这是因为您告诉select()要观察的一个或多个套接字已经准备好读取(和/或准备好写入),所以select()立即返回而不是阻塞……但接着代码忽略了在该套接字上实际地执行recv()(或send())操作。在未能读取/写入任何数据后,事件循环将尝试通过再次调用select()来休眠,但是当然,套接字的数据(或缓冲区空间,在准备写入的情况下)仍在等待处理,因此select()再次立即返回,buggy代码再次忽略执行recv()(或send()),如此周而复始,速度非常快:)

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

我建议在调用select()之前和之后立即放置一些printf(或您喜欢的等效物),并在重现故障时观察该输出。这将向您显示旋转是否发生在单个select()调用内,或者是否有某些原因使select()一遍又一遍地立即返回。


7
这是我在SO上看到的最好的答案之一,尤其是当问题中没有源代码时。 - It'sPete
先生,你是救世主。 - teoring

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