Helder AC
Helder AC

Reputation: 376

How to avoid busy looping in specific case

I have a problem which I don't really know how to solve. I have a program that multiplexes multiple connections. Those connections are receiving streaming data all at the same time. I had to configure non blocking sockets as the streams have different bitrates. Now what I actually did is keep those sockets in an array looping through them and detecting with a select if there is data to read and proceding to the next element in the array if not. It works very well except for teh fact that teh CPU is always at 100%. Actually if at some point there is nothing to read from any socket it will still loop. I don't really know how it would be possible to block the loop whenever no data is available on any socket and just keep going when there is data. I think this may be the solution but I don't really see how I could do this. The program has to be very responsive though as it is a UDP stream recorder and if it blocks for too long, this will produce lags in the file.

I thank you a lot.

PS.: Just for info I am still learning so please don't blame me even if the solution may be obvious.


EDIT:

here's some pseudo code:

When a recording request comes in, I create a new connection and connect to the stream address. If it succeeds, I build my fdset using following function:

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;
        }
    }
}

Then the loop handling the connections:

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 */
                }
            }
        }
    }
}

PROBLEM: When I set timeout to timeout.tv_sec = 1 timeout.tv_usec = 0 everything works fine BUT i get 100% CPU usage! When I give NULL as timeout, the program blocks on the select() although there is data on the sockets.


SOLUTION:

Well I finally found the error! In the above code I set the timeout values only once before the main loop. Well the problem with that is that as for fdset, the timeout structure is modified by the select() function. So after the first correct timed out select, the timeout structure gets modified by the select() function and is set to 0. This results in 0 timeout, thus the problem that the next time the loop gets to the select function, the timeout given to the select is 0!!!

Thanks a lot still to those who tried to help! I apreciate it =)

Upvotes: 2

Views: 206

Answers (2)

Jis Ben
Jis Ben

Reputation: 155

You could also use sleep after you check all your streams to give up CPU at the end of your loop. This way you don't depend on a single stream to have incoming data sometime in the near future, at the risk of not servicing your other streams.

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409356

The timeout of the select call can be NULL which means to wait forever.

Upvotes: 4

Related Questions