POSIX Input/Output multiplexing Select


Example

Select is another way to do I/O multiplexing. One of it's advantages is an existance in winsock API. Moreover, on Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this. (POSIX.1 permits either behavior.)

Both poll and select have ppoll and pselect alternatives, which allow handling incoming signals during waiting for event. And both of them become slow with huge amount of file descriptors (one hundred and more), so it would be wise to choose platform specific call, e.g. epoll on Linux and kqueue on FreeBSD. Or switch to asynchronous API (POSIX aio e.g. or something specific like IO Completion Ports).

Select call has the following prototype:

int select(int nfds, fd_set *readfds, fd_set *writefds,
       fd_set *exceptfds, struct timeval *timeout);

fd_set is a bitmask array of file descriptors,

nfds is the maximum number of all file descriptors in set + 1.

Snippet of working with select:

fd_set active_fd_set, read_fd_set;
FD_ZERO (&active_fd_set); // set fd_set to zeros
FD_SET (sock, &active_fd_set); // add sock to the set
// # define FD_SETSIZE sock + 1
while (1) {
    /* Block until input arrives on one or more active sockets. */
    read_fd_set = active_fd_set; // read_fd_set gets overriden each time
    if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) {
        // handle error
    }
    // Service all file descriptors with input pending.
    for (i = 0; i < FD_SETSIZE; ++i) {
        if (FD_ISSET (i, &read_fd_set)) {
            // there is data for i
    }
}

Note, that on most POSIX implemetations file descriptors associated with files on disk are blocking. So writing to file, even if this file was set in writefds, would block until all bytes won't be dumped to disk