Inter-Process Communication

select, poll, and I/O multiplexing

/ EE-poll /

Suppose your program is talking to a hundred clients at once over a hundred connections. If you call read() on connection 1 and no data has arrived, the call blocks — and now you are stuck, unable to serve the other 99 even though one of them might have data waiting. One thread can only block on one thing. I/O multiplexing is the way out: a single call that watches many descriptors at the same time and tells you which ones are ready, so you only ever read or write the ones that will not block.

The classic calls are select() and poll(). You hand them a list of file descriptors you care about and ask 'which of these are ready to read, ready to write, or in error?' The call blocks until at least one is ready (or a timeout fires), then returns the ready set. Now you loop over just those and act on them, knowing each operation will proceed immediately. This is 'readiness' notification: the kernel does not move your data, it just tells you 'descriptor 14 has data you can read now.' One thread, many connections, no wasteful blocking on any single one. select() and poll() do the same job with different interfaces (poll() scales a little better and has no hard descriptor-number limit).

The honest limitation is scale: select() and poll() must scan every descriptor on every call, so watching 10,000 connections gets slow — the cost grows with the total number watched, not the number that are actually ready. That is why Linux added epoll and the BSDs added kqueue: same idea (wait on many, learn what is ready), but they register your interest once and report only the descriptors that changed, so cost scales with activity, not with the total. These are the engine inside every high-concurrency server. The model here is readiness (tell me when I can act), as opposed to completion (do the work and tell me when it is done), which is a different style some newer interfaces use.

fd_set r; FD_ZERO(&r); FD_SET(sock_a,&r); FD_SET(sock_b,&r); select(maxfd+1, &r, NULL, NULL, NULL); /* blocks until a or b is readable */ if (FD_ISSET(sock_a,&r)) read(sock_a,...); /* read only the ready one */

Watch many, block once, act only on what is ready. That is how one thread serves thousands of connections.

select() and poll() report readiness but you still do the read()/write() yourself, and they rescan all watched descriptors each call — fine for a few, slow for thousands. For huge counts, epoll (Linux) or kqueue (BSD/macOS) scale far better.

Also called
I/O multiplexingreadiness notificationselect/poll/epoll/kqueue輸入輸出多工