~/learn

Shared Memory

The fastest IPC — mapping the same memory into multiple processes with mmap and POSIX shared memory, and why it needs explicit synchronization.

Shared memory is the fastest form of IPC: instead of copying data through the kernel (as pipes do), two processes map the same physical pages into their address spaces and read and write them directly. The trade-off is that it provides no synchronization of its own — you must add that yourself.

Why it's fast

With pipes or sockets, every byte is copied from one process into the kernel and out to another. With shared memory, once the region is set up there is no copying and no kernel involvement on each access — both processes simply dereference pointers into the same RAM. That speed is why it's used in databases, high-performance computing, and multimedia.

mmap

mmap() maps something into your address space and returns a pointer. It has two main uses:

  • File-backed — map a file so its contents appear as memory; writes go back to the file.
  • Anonymous (MAP_ANONYMOUS) — plain memory not backed by any file.

The visibility of writes depends on the flag:

  • MAP_SHARED — changes are visible to other processes mapping the same object.
  • MAP_PRIVATE — copy-on-write; changes stay private to your process.
int fd = open("data.bin", O_RDWR);
char *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
p[0] = 'X';          // writes straight through to the file / shared region
munmap(p, len);      // unmap when done  (msync() forces a file flush)

The modern, file-descriptor-based API. Create (or open) a named object, size it, then mmap it — the object lives under /dev/shm/:

int fd = shm_open("/mydata", O_CREAT | O_RDWR, 0644);
ftruncate(fd, len);                                   // set its size
void *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// ... share via p ...
shm_unlink("/mydata");                                // remove the object

Because it uses file descriptors, it integrates cleanly with the rest of the POSIX API and is cleaned up when unlinked.

System V shared memory (legacy)

The older API is still common: shmget() (create/get by a key from ftok()), shmat() / shmdt() (attach/detach), and shmctl(..., IPC_RMID) to remove. Segments persist until removed or reboot — inspect them with ipcs -m and clean up with ipcrm. Prefer POSIX for new code.

You must synchronize

Shared memory is just memory — nothing stops two processes writing the same bytes at once, so the synchronization rules apply across processes too:

Protect access with process-shared primitives — POSIX named semaphores (sem_open), process-shared mutexes (a pthread_mutex_t with PTHREAD_PROCESS_SHARED placed in the shared region), or file locks.

Practice / lab

  • mmap a file, modify it through the pointer, and confirm the change persists after munmap.
  • Write a POSIX writer/reader pair: one shm_open+ftruncate+mmap+writes, the other reads; clean up with shm_unlink.
  • Put a counter in shared memory, increment it from several processes, watch it race, then fix it with a named semaphore.
  • Compare throughput of shared memory vs. pipes vs. files.

Homework

  • IPC-3: Shared Array — a shared_array class shared between processes, synchronized with a cross-process semaphore.

References & resources

Required

Optional / enrichment

Self-check

  1. Why is shared memory the fastest IPC mechanism?
  2. What is the difference between MAP_SHARED and MAP_PRIVATE?
  3. Which calls create and size a POSIX shared-memory object, and where does it appear?
  4. How does System V shared memory differ from POSIX, and how do you inspect/remove it?
  5. Why does shared memory require explicit synchronization, and what can provide it?

On this page