I/O Multiplexing: select(), poll() & Non-Blocking Sockets
Idea in plain words
I/O Multiplexing enables a single process to monitor multiple file and socket descriptors simultaneously without multi-threading overhead.
Exam tip
High-yield exam topic (Very High).
Explanation
Traditional blocking I/O causes a single-threaded server to stall indefinitely if an accepted client is idle. Non-blocking I/O with busy-waiting exhausts CPU cycles. I/O multiplexing delegates descriptor monitoring to the kernel. select() blocks until at least one monitored descriptor becomes ready for reading, writing, or encounters an exceptional condition. This pattern forms the core foundation of high-concurrency event-driven network daemons, telnet clients, and proxy forwarders.
Key points
- select() monitors three descriptor sets (read, write, exception) with an optional timeout.
- FD manipulation macros: FD_ZERO, FD_SET, FD_CLR, FD_ISSET.
- select() limitations: Constrained by FD_SETSIZE (default 1024) and requires O(N) linear scanning of the descriptor set upon return.
- poll() replaces bitmasks with an array of struct pollfd (fd, events, revents), removing the FD_SETSIZE limitation.
Example
Example
The 5 Unix I/O Models: 1. Blocking I/O, 2. Non-blocking I/O, 3. I/O Multiplexing (select/poll), 4. Signal-driven I/O (SIGIO), and 5. Asynchronous I/O (POSIX aio_read).
Code examples
fd_set read_fds;
struct timeval tv = {5, 0}; // 5-second timeout
FD_ZERO(&read_fds);
FD_SET(listenfd, &read_fds);
FD_SET(STDIN_FILENO, &read_fds);
int max_fd = (listenfd > STDIN_FILENO ? listenfd : STDIN_FILENO) + 1;
int nready = select(max_fd, &read_fds, NULL, NULL, &tv);
if (nready > 0) {
if (FD_ISSET(listenfd, &read_fds)) {
// Accept new incoming network connection
}
if (FD_ISSET(STDIN_FILENO, &read_fds)) {
// Read console input from terminal
}
}
Exam questions
- [10 Marks] Explain the select() system call, its parameters, fd_set manipulation macros, and limitations compared to poll().
- [6 Marks] Differentiate between close() and shutdown() system calls. Discuss SHUT_RD, SHUT_WR, and SHUT_RDWR.