Interview Prep Zoneby CuriouserLabs

Question 5 of 5 · senior level

Compare IPC mechanisms — pipes, shared memory, sockets, message queues, signals. How do you choose?

🎤 Say this first

Two families: message passing (pipes, sockets, message queues — the kernel copies data between address spaces; simple, safe, composable) and shared memory (mmap'd region both processes map — zero-copy, fastest by far, but you've reimported every synchronization problem threads have). Choose by coupling and location: pipes for parent-child streaming (shell!), Unix domain sockets as the local workhorse (bidirectional, FD-passing, socket API — sidecars, Docker daemon), TCP sockets when distribution is even possible later, shared memory only when copy cost is measured to matter (Chrome, databases' buffer pools, Aeron-style rings). Signals are not IPC — they're process control (SIGTERM handling), don't build protocols on them.

The full picture

MechanismModelSweet spotWatch out
Pipe / FIFObyte stream, kernel copyparent↔child pipelines; ls | grepunidirectional; 64KB buffer backpressure = your flow control
Unix domain socketstream/dgram, kernel copylocal daemons, sidecars; can pass FDs!still syscalls + copies; local only
TCP socketstream over networkanything that may distributelatency, partial reads, the network fallacies
POSIX MQdiscrete prioritized messagesembedded/RT patternsrare in server land — Kafka/Redis took this niche
Shared memory + semszero-copy regionhighest throughput/lowest latency (rings, buffer pools)you own synchronization, layout, versioning, corruption
  • The core trade stated once: message passing pays a copy to keep isolation; shared memory drops the copy and the isolation together. Everything else is packaging.
  • FD passing over Unix sockets (SCM_RIGHTS) is the underrated superpower — hand a connected socket to a worker process: how nginx/systemd socket activation and zero-downtime listeners work.
  • Backpressure is built-in: a full pipe blocks the writer — sometimes exactly what you want (shell pipelines self-throttle), sometimes a distributed-deadlock seed (two processes both blocked writing to each other — always drain stdout/stderr of child processes; the classic Process.waitFor hang).
  • Modern default in practice: within a host, Unix sockets (or gRPC over UDS); across hosts, TCP/gRPC/queues; shared memory only with a profiler's blessing — and note that containers in a K8s pod can share /dev/shm, which is how ML sidecars move tensors.

🔄 Likely follow-up questions

  • How does SCM_RIGHTS FD passing enable zero-downtime socket handoff?
  • Why is 'signals as IPC' an anti-pattern, and what are signals actually for in a service (SIGTERM)?
  • Sketch a shared-memory ring buffer between two processes — what synchronization does it need?