Inter-Process Communication

readiness and backpressure

Two ideas sit at the heart of how processes move data without drowning each other. The first is readiness: knowing when an operation can proceed without making you wait. The second is backpressure: what happens, and what it tells you, when one side produces data faster than the other can consume it. Together they answer 'when can I act, and what stops me from overwhelming the other end?'

Start with blocking versus non-blocking, because it shapes both. A blocking call waits until the work can happen: read() on an empty pipe sleeps until data arrives; write() to a full pipe sleeps until space frees up. A non-blocking call (set with the O_NONBLOCK flag) never waits — if it cannot proceed right now it returns immediately with EAGAIN/EWOULDBLOCK, meaning 'not ready, try later.' Non-blocking mode is what pairs with select()/poll(): you only attempt the operation once the multiplexer says the descriptor is ready, so you never sleep. Readiness, then, is the kernel telling you 'this will not block right now.'

Backpressure is the quietly brilliant part of pipes, sockets, and queues. Every such channel has a finite buffer. When a fast producer fills that buffer because the consumer is slow, the producer's next write() blocks (or returns EAGAIN). That stall is not a bug — it is the signal 'slow down, the reader cannot keep up,' and it automatically throttles the producer to the consumer's pace, with no data lost and no unbounded memory growth. In a shell pipeline this is why cat a-huge-file | slow-filter never blows up memory: cat is paused by a full pipe whenever slow-filter lags. The honest caveat: backpressure protects you only if you respect it — ignore EAGAIN and spin, or read in a tight loop, and you burn CPU; mishandle a blocking write that never drains, and you deadlock.

Blocking: write(fd, buf, n); /* sleeps if the pipe is full — natural backpressure */ Non-blocking: fcntl(fd, F_SETFL, O_NONBLOCK); n = write(fd, buf, n); if (n < 0 && errno == EAGAIN) { /* not ready: wait via poll(), retry later */ }

A full buffer blocking the writer is not a failure — it is flow control telling the fast side to wait for the slow side.

Backpressure is a feature, not a bug: a blocked write means the channel is doing flow control for you. The mistake is to fight it — busy-looping on EAGAIN wastes CPU; the right move is to wait for readiness with poll()/epoll, then retry.

Also called
backpressureflow controlblocking vs non-blocking IPC背壓流量控制