posts - 15, comments - 9, trackbacks - 0, articles - 0

(1) 最近在linux下开发了一个通信服务程序,主要负责与客户端建立连接,转发客户端的消息给后台信息处理模块,同时也将后台的处理结果转发给客户端。
由于在windows下已经有了一个相同功能的程序,便做了移植。移植到linux下功能是可以实现的,但发现此程序的cpu利用率非常高。经分析发现是linux下的
select调用与windows的select调用的一个区别造成的。

程序处理流程如下:

 1bool msg_recv_thread(void)
 2{
 3    int          max = 0;
 4    fd_set       readfds;         // 结果集
 5    struct timeval  RevTimeOut;
 6    RevTimeOut.tv_sec = 1;        // 设定select的超时时间为1s
 7    RevtimeOut.tv_usec = 0;
 8
 9    while(1)
10    {
11        FD_SET(conn_socket, &readfds);
12        max = (max > conn_socket) ? max : conn_socket;
13        int ret = select(max+1&readfds, NULL, NULL, &RevTimeOut);
14
15        if (ret <= 0)
16        {
17            continue;
18        }

19
20        if (FD_ISSET(conn_socket, &readfds) != 0)
21        {
22            // 接受连接请求处理……
23        }

24
25        // 其他处理……
26}

windows下这样的流程没有问题,但是在linux下,select调用在设定的超时时间内等待时会不断地更新最后一个参数,将其实时更新为离设定的超时时间的时间差,直到这个值被更新为0,即到达超时时间时select函数返回。在上面的程序段中,第一次循环时select的超时参数值为1s,当第一次循环完毕时,RevTimeOut的值已经被变成了0,这样以后的循环就会是无阻塞的,即如果selec没有收到任何的请求便立刻返回,然后继续循环,这样就形成了死循环,从而耗光了cpu。

将上述程序段中的5-7行移到第13行以前,问题便解决了。


【总结】
            这里涉及到一个编程习惯的问题,本人经验欠缺,在做windows到linux的移植时一直认为既然windows下正确那么linux一定也是正确的,完全没有考虑到两个OS好之间的系统调用方面的区别,导致开始时就搞错了方向,浪费了不少时间。希望大家不要犯我这样的错误。

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理