[问题记录] 服务器select设置超时时间导致cpu过高

在做onvif开发的时候,因为侦听端口可能会被修改,因此accept之前通过select侦听,
select设置超时时间,所以即使没有客户端连接,超时后也可以修改侦听端口。
但是测试时发现select设置了超时时间后cpu占用率很高,达到80%以上。

经过排查和查资料发现是select超时时间使用的问题。最初设置超时时间后,进入循环,有客户端连接则处理。
但实际上select设置超时时间时,time_out参数传入的是指针,每次select都是使用time_out剩余的时间。
多次调用后time_out的值就被减为0 了,这时相当于全速运行,因此cpu高
正确做法是:
1、类似FD_SET,每次调用select都重置time_out,即每次循环都要重新给time_out赋值。
2、使用pselect替换select,pselect中传入的time_out参数是值传递,不会改变time_out的值,即每次超时时间一样;


在man中也有说明:
DESCRIPTION
       select()  and  pselect()  allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of
       I/O operation (e.g., input possible).  A file descriptor is considered ready if it is possible to perform the corresponding I/O operation (e.g., read(2))  without
       blocking.

       The operation of select() and pselect() is identical, with three differences:

       (i)    select() uses a timeout that is a struct timeval (with seconds and microseconds), while pselect() uses a struct timespec (with seconds and nanoseconds).

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

            select会更新timeout参数的值,每次调用都是用上次剩余的时间,多次调用或一次超时返回后timeout就一直为0,频繁调用导致CPU高。pselect则不会改变这个参数。

       (iii)  select() has no sigmask argument, and behaves as pselect() called with NULL sigmask.


正确应该每次都重新赋值(或采用pselect)

  struct timeval time_out;
  time_out.tv_sec = 2;
  time_out.tv_usec = 0;
  ret = select(listen_fd + 1, &read_fd, NULL, NULL, &time_out);
  
  
  这点要特别注意,很容易忽视。

你可能感兴趣的:(网络编程)