Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

irritating select() behaviour in c

while (xxx) {
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec=0;
    FD_ZERO(&set); 
    FD_SET(sd,&set);

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
    xxxxx
}

works fine, however

FD_ZERO(&set); 
FD_SET(sd,&set);

while (xxx) {
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec=0;

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
    xxxxx
}

doesn't. It works the first time around, but the next time it runs through the while loop it gets a timeout even if the sd socket receives data. It seems to me to be a waste of resources to have to empty and fill set every time.

Anybody have a good explanation why this is, and even better, perhaps a suggestion how to avoid it?

like image 826
deadcyclo Avatar asked Nov 12 '08 23:11

deadcyclo


2 Answers

select modifies its arguments. You really do have to re-initialize it each time.

If you're concerned about overhead, the cost of processing the complete FD_SET in the kernel is somewhat more significant than the cost of FD_ZERO. You'd want to only pass in your maximum fd, not FD_SETSZIZE, to minimize the kernel processing. In your example:

switch (select((sd + 1),&set,NULL,NULL,&timeout))

For a more complex case with multiple fds, you typically end up maintaining a max variable:

FD_SET(sd,&set);
if (sd > max) max = sd;
... repeat many times...

switch (select((max + 1),&set,NULL,NULL,&timeout))


If you will have a large number of file descriptors and are concerned about the overhead of schlepping them about, you should look at some of the alternatives to select(). You don't mention the OS you're using, but for Unix-like OSes there are a few:

  • for Linux, epoll()
  • for FreeBSD/NetBSD/OpenBSD/MacOS X, kqueue()
  • for Solaris, /dev/poll

The APIs are different, but they are all essentially a stateful kernel interface to maintain a set of active file descriptions. Once an fd is added to the set, you will be notified of events on that fd without having to continually pass it in again.

like image 126
DGentry Avatar answered Oct 18 '22 09:10

DGentry


Read the select man page. The returned set is only the file descriptors that are ready to be used. You are supposed to use FD_ISSET to check each one if it is set or not.

Always initialize the fd_set right before using it.

like image 44
Greg Rogers Avatar answered Oct 18 '22 07:10

Greg Rogers