A strong answer
When two processes communicate over a pipe or Unix domain socket, every message pays for two memory copies and two kernel context switches: the writer calls write(), copying bytes from its user-space buffer into a kernel ring buffer, and the reader calls read(), copying those bytes from the kernel ring buffer into its own user-space buffer. With POSIX shared memory (shm_open + ftruncate + mmap with MAP_SHARED), the kernel maps the exact same physical RAM frames into the page tables of both processes. Once mmap returns, reading and writing shared data is just ordinary user-space memory access (*ptr = value) at L1/L3 cache speeds—zero system calls and zero kernel copies on the hot path.
That raw speed comes with three engineering responsibilities that pipes handle automatically:
- Explicit synchronization: Because both processes read and write the same physical RAM concurrently, you must guard the region using C11 atomics (
_Atomic), unnamed POSIX semaphores initialized withpshared = 1, orpthread_mutex_tconfigured withPTHREAD_PROCESS_SHARED(andPTHREAD_MUTEX_ROBUSTin case a holder crashes). - Relative offsets instead of raw pointers: The kernel may map the shared segment at virtual address
0x7f0000100000in Process A and0x7f8800400000in Process B. Storing a raw C pointer (struct node *next) inside shared memory will crash Process B; data structures inside shared memory must use byte offsets (size_t next_offset) from the base of the mapping. - Kernel persistence: Unlike anonymous pipes that vanish when all descriptors close, a POSIX shared memory object in
/dev/shmpersists untilshm_unlink("/name")is called or the machine reboots.
What the interviewer is listening for
- Explains the page-table mechanism: two virtual address ranges in different processes pointing to the same physical RAM page frames via
MAP_SHARED. - Identifies the pointer-relocation problem (ASLR maps the region at different base virtual addresses per process, requiring offset-based indexing).
- Mentions
PTHREAD_PROCESS_SHARED/PTHREAD_MUTEX_ROBUST,pshared = 1semaphores, or lock-free ring buffers with acquire/release atomics for synchronization.
Common mistakes
- Storing raw C pointers (
T *) orpthread_mutex_tinitialized with default thread-private attributes inside shared memory. - Writing to a newly created
shm_openregion before sizing it withftruncate, which raisesSIGBUS. - Using
MAP_PRIVATEinstead ofMAP_SHARED, which silently turns writes into private Copy-on-Write pages invisible to other processes.