Shared Memory
The idea
Shared memory allows two or more processes to map the same physical frames into their address spaces. Once mapped, the processes can read and write the shared region directly, without kernel mediation on each access. This is the fastest IPC mechanism because data transfer involves no system calls (beyond the initial setup).
In POSIX, shared memory is established through the shmget() / shmat() (System V) or shm_open() / mmap() (POSIX) interfaces.
Setup (POSIX mmap approach)
// Process A (creator)
int fd = shm_open("/myshm", O_CREAT | O_RDWR, 0600);
ftruncate(fd, 4096); // set size
void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
// addr now points to shared memory
// Process B (attacher)
int fd = shm_open("/myshm", O_RDWR, 0600);
void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
Both processes can now read and write *addr. A write by A is immediately visible to B because both map the same physical page (the MMU’s cache-coherence protocol ensures this on multicore systems). No kernel involvement on each access.
Synchronisation
Shared memory provides no synchronisation. If A and B write to the same location concurrently, the result is undefined. Processes must use additional synchronisation primitives:
- POSIX semaphores (
sem_open,sem_wait,sem_post) — the standard approach. futex— the Linux fast user-space mutex, used bypthreads. A contended lock triggers afutexsystem call; uncontended operations stay in user space.- Atomic operations (C11
_Atomic, GCC__atomic) — for lock-free data structures.
The lack of built-in synchronisation is both a weakness (programmes are harder to write correctly) and a strength (programmes can choose the synchronisation model that best fits their access pattern).
Comparison with pipes
| Shared memory | Pipes | |
|---|---|---|
| Data transfer cost | Memory copy (or zero if the data structure is accessed in place) | System call + kernel copy (user → kernel → user) |
| Synchronisation | Must be added explicitly | Built-in: read blocks, write blocks |
| Naming | By key or path name | Anonymous (inherited) or path name (FIFO) |
| Flow control | None — a fast writer can overrun a slow reader | Pipe buffer provides natural back-pressure |
Shared memory is faster for large, structured data (e.g., a database buffer pool, a video frame buffer). Pipes are simpler and safer for streaming data where flow control is needed.
Security concerns
Shared memory bypasses the kernel’s permission checks after setup. Once a process has the file descriptor (or key) for a shared-memory region, it can access the data. Access control is enforced at shm_open() or shmget() time, not on each access. This matches the “check once, use many” pattern of UNIX file descriptors.
Message queues
POSIX message queues (mq_open, mq_send, mq_receive) provide an intermediate point between shared memory and pipes: structured messages with priorities, kernel-buffered, with synchronisation built in. They are less commonly used than pipes (for streaming) and shared memory (for bulk transfer) but offer a useful hybrid.
Summary
- Shared memory is the fastest IPC — no kernel mediation per access.
- It requires explicit synchronisation (semaphores, futexes, atomics).
- Pipes provide built-in synchronisation and flow control at the cost of system-call overhead and kernel copies.
- Message queues offer structured, prioritised messages as a middle ground.