当前位置:   article > 正文

select() 的 timeout 陷阱_select timeout

select timeout

今天说说 select() 接口的最后一个参数 timeout 陷阱。

说这个是陷阱,其实对 API 作者有点不公平,

POSIX 2001.12 的说明上已经明确的标注,见下图。 

(ii)   select() may update the timeout argument to indicate how much time was left.  pselect() does not change this argument.

select() 这个接口在调用完以后可能会更新 timeout 参数,

用于标识 timeout 剩余的时间,

例如:上层用户希望进行 3 秒的 timeout,

而接口内部在 1 秒的时间操作完成了(可能成功也可能失败)返回了,

这个时候 timeout 的值会更新为 2 秒。

对于有点偏执型的 programmer,例如我,

潜意识会对循环内赋值有抵触情绪,

在调用 select() 的 timeout 会倾向于在循环外部进行赋值,以降低不必要的 CPU 消耗,

这个原本是很好的潜意识设定,偏偏误进了泥淖,见下图。

  1. timeout.tv_sec=10;
  2. timeout.tv_usec=0;
  3. while(condition()) {
  4.   if (select(fd, rdset, NULL, NULL, &timeout) > 0) {
  5.   }
  6. }

以上面代码段为例,在循环体外部,timeout 赋值 10 秒,

设计者很清晰地实现 select() 调用最长效时为 10 秒,

但任何的处理都是要花费时间的,当 select() 第一次调用完成再次进入循环体时,

这个 timeout 的值已经背更新为”剩下的时间“,如 9 秒,

因此它的数值已经抵消掉 select() 调用所用的时间,

在多次循环的之后,这个 timeout 将无疑地等于零,

这个时候,select() 调用的设计不再符合设计者的初衷,

而是一种恶意霸占 CPU% 的 dead loop 行为。

在 code review 时要考虑这种行为场景的异常。

再回到图①文档说明中,

细心的人会发现,为什么中间会用 may 这个字眼呢?

难道作者的女朋友叫阿 may,是阿 may 去 update 的?

显然不是,

这里有一定历史原因,

关于 select() timeout 上的用法陷阱,很多资深的平台移植人员也掉进过,

FreeRTOS 平台调用 select,timeout 的值在调用前后保持不变,

只能说,这个 POSIX API 规范在跨平台中一点都不严谨,

因此,不建议过分使用该特性,

以免“善用刀剑者,死于刀剑之下”

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/225109
推荐阅读
相关标签
  

闽ICP备14008679号