Back to the map

Module 03 · Processes and threads · Lesson 5 of 7

Inter-process communication

How isolated processes exchange data: pipes, Unix domain sockets, shared memory, message queues and files. What each costs in copies and system calls, which give ordering or structure, and how the choice maps to sidecars and local services.

CoreShould-knowMid 12 min Updated Nov 2026

Why it matters

Processes are isolated on purpose, but real systems need them to cooperate: a shell pipeline, a web server talking to a local PHP or Python worker, an application and its sidecar proxy, a database and its replication helper, a browser's renderer and its main process. The mechanism chosen decides latency, throughput and how much code you write. A service mesh sidecar adds a hop through exactly these mechanisms to every request, which is why their cost matters.

The idea

Because processes cannot read each other's memory, every inter-process communication (IPC) mechanism goes through something the kernel provides: a kernel buffer that data is copied into and out of, a region of memory the kernel maps into both processes, or a file.

MechanismShapeCopies per messageFits
PipeOne-way byte stream between related processes (anonymous) or by name (FIFO)Two: into the kernel, out againShell pipelines, a parent feeding a child
Unix domain socketBidirectional stream or datagram, addressed by a file path; can pass file descriptorsTwo, but no network stackLocal services: database clients, Docker's API, app to sidecar
TCP over loopbackSame API as remote networkingTwo, plus the TCP/IP stackCode that might later run on another machine
Shared memoryA region mapped into both address spacesZero; processes read and write the same pagesHigh-throughput data exchange: video frames, analytics engines, databases
Message queue (POSIX or System V)Kernel-held queue of discrete messages, optionally with an order keyTwoDiscrete messages without a broker
Memory-mapped fileA file mapped into memory by several processesZero after the page cache holds itSharing large read-mostly data; persistence for free
SignalsA tiny notification, no payloadn/aLifecycle events only (stop, reload)
pipe or socketProcess AProcess BKernel bufferwrite: copyread: copyshared memoryProcess AProcess BShared pagesneeds locks or atomics
Copying IPC goes through a kernel buffer, costing a system call and a copy on each side. Shared memory maps the same physical pages into both processes, so data never moves; synchronisation becomes your problem.

Choosing a mechanism

  1. 1

    Default to sockets

    A Unix domain socket for same-host communication is fast, bidirectional, supports many clients, works with every language, and switches to TCP with an address change if the processes later move apart. It is what Postgres, Docker and most local daemons use.
  2. 2

    Reach for shared memory when copies dominate

    When you move hundreds of megabytes per second between processes, copies and system calls become the cost. Shared memory removes them, at the price of designing synchronisation (lock-free ring buffers, futexes) and handling a crashed peer that leaves shared state half-written.
  3. 3

    Use pipes for streams between related processes

    Simple, ordered and back-pressured: a full pipe blocks the writer, which naturally throttles a fast producer.
  4. 4

    Use files and memory maps for large read-mostly data

    Several processes mapping the same file share one copy in the page cache, which is how databases and search engines share index data across workers.

Structure on top of bytes

Pipes and stream sockets carry bytes, not messages. Something must define where one message ends: length prefixes, delimiters, or a protocol such as HTTP or gRPC over the socket. That framing and the serialisation of data into bytes often cost more than the IPC itself, which is why high-performance local paths use binary formats or shared memory with fixed layouts.

The sidecar case

A service mesh puts a proxy process next to every application, and every request goes app to proxy to network to proxy to app. Each local hop is IPC (usually loopback TCP or a Unix socket), adding tens to hundreds of microseconds and CPU for copying and parsing. That cost is small next to a network round trip, but it is why meshes increasingly move work into the kernel (eBPF) or into a per-node proxy instead of per-pod ones.

Trade-offs

Copying mechanisms are simple, safe and portable, and cost a copy and a system call per side. Shared memory is the fastest and hands you concurrency bugs and crash recovery. Sockets are the most flexible and carry the cost of framing and serialisation. The isolation that makes processes safe is exactly what makes them slower to talk to than threads.

In an interview

Use it for local architecture: "The app talks to its local cache daemon over a Unix domain socket, which avoids the TCP stack; if we split them onto different hosts we change the address to TCP and nothing else changes. The video pipeline passes frames through a shared-memory ring buffer because copying 4K frames between processes would dominate CPU."

Check yourself

A local analytics process receives 500 MB per second of event data from an ingest process on the same host over a loopback TCP connection, and profiling shows most CPU time in copying and system calls. What is the strongest fix?

Inter-process communication · Backplane