10/32 · 5 min
Talking across the boundary
Separate processes have separate memory, which is the point. When they need to cooperate, the kernel provides the channel.
Pipes
A one directional byte stream. What one writes, the other reads.
ls -l | grep '.txt' | wc -lThree processes, two pipes, running at the same time. grep does not wait for ls to finish; it processes lines as they arrive, which is why a pipeline over a huge file starts producing output immediately.
A pipe has a fixed buffer. A writer filling it blocks until the reader consumes some, which is flow control for free: a fast producer cannot exhaust memory because a slow consumer is not keeping up.
Named pipes are the same thing with a filesystem name, so unrelated processes can use one.
Message queues
Discrete messages rather than a stream, with the kernel preserving boundaries. Send three messages and the reader receives three, not one run together. A receiver can also pick by priority.
Shared memory
The fastest, because after setup there is no kernel involvement at all. Two processes map the same physical pages and read and write them as ordinary memory.
int fd = shm_open("/region", O_CREAT | O_RDWR, 0600);
ftruncate(fd, 4096);
void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);The catch is that the kernel provides no coordination. Nothing stops both writing at once, so a semaphore or mutex has to be added, and now you have all the problems of threads with none of the convenience.
Sockets
Work between processes on one machine (Unix domain sockets) and across a network (TCP, UDP) with the same interface. Slower than shared memory, and the only option once the processes are on different machines, which is why every distributed system ends up here.
| Mechanism | Speed | Boundaries kept | Across machines |
|---|---|---|---|
| Pipe | fast | no, a byte stream | no |
| Message queue | fast | yes | no |
| Shared memory | fastest | n/a, raw memory | no |
| Socket | slower | depends on protocol | yes |
Signals
Not really communication: one number, asynchronously delivered. SIGTERM asks a process to stop, SIGKILL cannot be caught and ends it immediately.
The difference matters when writing a service. Handling SIGTERM is how a process finishes its current request and closes connections cleanly, and a container runtime sends exactly that before resorting to SIGKILL.