Disclaimer: ChatGPT generated document.
Here's a comparison of select(), poll(), and epoll(), focusing on their differences, advantages, and disadvantages.
| Feature | select() |
poll() |
epoll() |
|---|---|---|---|
| Introduction | Oldest, POSIX | Newer, POSIX | Linux-specific |
| Max FD Limit | Limited by FD_SETSIZE (often 1024) |
No limit (depends on system) | No limit (depends on system) |
| Efficiency | O(n) (scans all FDs) | O(n) (scans all FDs) | O(1) (event-driven) |
| Memory Usage | Uses fixed fd_set (bitmask) |
Uses an array of pollfd structs |
Uses an efficient kernel structure |
| State Persistence | Needs to be reinitialized on every call | Needs to be reinitialized on every call | Persistent: Kernel keeps track of watched FDs |
| Best Use Case | Small number of FDs | Small to medium number of FDs | Large-scale applications |
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);- Uses an array of
pollfdstructs, instead of a bitmask. nfdsis the number of file descriptors to check.timeoutcan be:0→ Non-blocking.-1→ Block indefinitely.- Custom time in milliseconds.
#include <stdio.h>
#include <poll.h>
#include <unistd.h>
int main() {
struct pollfd fds;
fds.fd = 0; // stdin
fds.events = POLLIN; // Wait for input
int timeout = 5000; // 5 seconds
printf("Waiting for input...\n");
int result = poll(&fds, 1, timeout);
if (result == -1) {
perror("poll");
} else if (result == 0) {
printf("Timeout: No input received.\n");
} else {
if (fds.revents & POLLIN) {
printf("Data is available on stdin!\n");
}
}
return 0;
}✅ No FD_SETSIZE limit.
✅ Uses an array instead of a bitmask, making it more flexible.
✅ Supports more event types, like POLLIN, POLLOUT, POLLERR.
❌ O(n) complexity, still inefficient for large FDs.
❌ Must reinitialize pollfd array every call.
🔹 Linux-specific (not available on macOS, BSD, or Windows)
🔹 Best for high-performance, large-scale applications (e.g., web servers, databases, chat apps)
#include <sys/epoll.h>
int epoll_create1(int flags);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);-
Create an epoll instance
int epfd = epoll_create1(0);
-
Add, modify, or remove FDs from the epoll set.
struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = sockfd; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
-
Wait for events
struct epoll_event events[10]; int num_events = epoll_wait(epfd, events, 10, -1);
#include <stdio.h>
#include <sys/epoll.h>
#include <unistd.h>
int main() {
int epfd = epoll_create1(0);
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = 0; // stdin
epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &ev);
printf("Waiting for input...\n");
struct epoll_event events[1];
int result = epoll_wait(epfd, events, 1, 5000); // 5s timeout
if (result == -1) {
perror("epoll_wait");
} else if (result == 0) {
printf("Timeout: No input received.\n");
} else {
printf("Data is available on stdin!\n");
}
close(epfd);
return 0;
}✅ O(1) complexity → Handles large numbers of FDs efficiently.
✅ Event-driven → Doesn't scan all FDs like select()/poll().
✅ Persistent state → Kernel tracks monitored FDs.
❌ Linux-only.
❌ More complex API than select()/poll().
❌ Not as portable as poll().
| Use Case | Best Choice |
|---|---|
| Small number of FDs (≤1024) | select() or poll() |
| Medium number of FDs (~few thousand) | poll() |
| Large number of FDs (e.g., web servers) | epoll() (Linux-only) |
Would you like a deeper dive into epoll() with edge-triggered vs level-triggered modes? 🚀
