如何避免在特定情况下忙于循环

时间:2012-06-08 07:59:00

标签: c linux networking

我有一个问题,我真的不知道如何解决。我有一个多路复用多个连接的程序。这些连接正在同时接收流数据。我必须配置非阻塞套接字,因为流具有不同的比特率。现在我真正做的是将这些套接字保存在一个循环遍历它们的数组中,然后使用select检测是否有数据要读取,并且如果没有,则会对数组中的下一个元素进行处理。 它工作得很好,除了teh CPU总是100%。实际上,如果在某些时候没有任何东西可以从任何套接字读取它仍然会循环。我真的不知道在任何套接字上没有数据可用时如何阻止循环,只有在有数据时才继续运行。我认为这可能是解决方案,但我真的不知道如何做到这一点。该程序必须非常敏感,因为它是一个UDP流记录器,如果它阻塞太长时间,这将在文件中产生滞后。

我非常感谢你。

PS:仅供参考我还在学习,所以请不要责怪我,即使解决方案可能很明显。


编辑:

这里有一些伪代码:

当录制请求进入时,我创建一个新连接并连接到流地址。如果成功,我使用以下函数构建我的fdset:

build_fdset()
{
    int ii;
    /* */
    FD_ZERO(&fdset);
    /* */
    for (ii = 0; ii < max; ii++)
    {
        if (astRecorder[ii].bUsed != FALSE && astRecorder[ii].socket != INVALID_SOCKET)
        {
            FD_SET(astRecorder[ii].socket,&fdset);
            /* */
            if (astRecorder[ii].socket > maxSocket)
                maxSocket = astRecorder[ii].socket;
        }
    }
}

然后处理连接的循环:

main_loop()
{
    struct timeval timeout;
    /* */
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    /* */
    for (;;)
    {   
        memcpy(&fdset_cpy,&fdset,sizeof(fdset));

        int ret = select((maxSocket + 1) , &fdset_cpy, NULL, NULL, &timeout);

        if (iSelectRet <= 0)
            continue;
        else
        {
            int ii;

            for(ii = 0; ii < max; ii++)
            {
                if ((recorders[ii].bUsed) && (FD_ISSET(recorders[ii].socket, &fdset_cpy)))
                {
                    /* receive from socket */
                    /* handle received data */
                }
            }
        }
    }
}

问题:当我将超时设置为timeout.tv_sec = 1 timeout.tv_usec = 0时一切正常但是我获得了100%的CPU使用率!当我将NULL作为超时时,程序会在select()上阻塞,尽管套接字上有数据。


解决方案:

好吧我终于找到了错误!在上面的代码中,我在主循环之前只设置了一次超时值。那么问题是,对于fdset,超时结构由select()函数修改。因此,在第一次正确的超时选择之后,select()函数会修改超时结构,并将其设置为0.这会导致0超时,从而导致下一次循环到达select函数的问题,给出超时选择是0 !!!

非常感谢那些试图帮助的人!我apreciate它=)

2 个答案:

答案 0 :(得分:4)

select来电的超时时间可以是NULL,这意味着要永远等待。

答案 1 :(得分:0)

在检查完所有流后,在循环结束时放弃CPU,也可以使用sleep。这样,您就不会依赖单个流在不久的将来某个时间传输数据,而存在不为其他流提供服务的风险。