Unlocking Linux Shared Memory: Deep Dive into IPC Mechanics and Implementation
This article thoroughly explains Linux shared memory, covering its advantages over other IPC methods, the kernel data structures, virtual‑physical mapping, creation and destruction APIs, copy‑on‑write behavior, and provides complete example code for inter‑process communication.
Inter‑Process Communication (IPC) and Shared Memory
In Linux each process has an isolated virtual address space. To exchange data processes must use IPC mechanisms. Shared memory is the fastest IPC because it lets multiple processes map the same physical memory region, eliminating copies between user space and kernel space.
Why Shared Memory Is Fast
Data is read/written directly in the shared physical page.
No double copy as required by pipes or message queues.
Ideal for high‑throughput or real‑time workloads such as video processing or image recognition.
Comparison with Other IPC
Speed : No data copying, therefore lower latency.
Data volume : Limited only by available physical memory.
Synchronization : Shared memory provides no built‑in sync; developers must use semaphores, mutexes, etc., to avoid race conditions.
Mapping Principles of Shared Memory
Linux uses page tables to translate virtual pages (typically 4 KB) to physical page frames. When a process calls shmat, the kernel:
Looks up the shmid in its internal list to obtain the segment’s metadata.
Allocates a suitable virtual address range (or uses the address supplied by the caller).
Creates page‑table entries that map the chosen virtual range to the physical pages of the segment, setting permission bits according to the shmflg flags.
Increments the segment’s attachment count.
The reverse operation ( shmdt) removes those page‑table entries and decrements the count.
Copy‑On‑Write (COW)
If a process writes to a page that is marked read‑only, the kernel allocates a new physical page, copies the original contents, updates the page‑table entry to writable, and clears the COW flag. This saves memory when most accesses are reads.
Kernel Data Structures
The kernel represents a shared memory segment with two main structures.
struct shmid_ds (user visible)
struct shmid_ds {
struct ipc_perm shm_perm; /* UID, GID, mode */
size_t shm_segsz; /* size in bytes */
time_t shm_atime; /* last attach */
time_t shm_dtime; /* last detach */
time_t shm_ctime; /* creation/modification */
pid_t shm_cpid; /* creator PID */
pid_t shm_lpid; /* last operator PID */
shmatt_t shm_nattch;/* current attachment count */
/* additional fields may exist depending on kernel version */
};struct ipc_perm
struct ipc_perm {
key_t key; /* unique identifier */
uid_t uid; /* owner UID */
gid_t gid; /* owner GID */
uid_t cuid; /* creator UID */
gid_t cgid; /* creator GID */
unsigned short mode; /* permission bits */
unsigned short seq; /* sequence number */
};These structures store permissions, size, timestamps, and the reference count that determines when the kernel can reclaim the segment.
struct shmid_kernel (kernel private)
struct shmid_kernel {
struct kern_ipc_perm shm_perm; /* extended permission block */
struct file *shm_file; /* VFS file representing the segment */
unsigned long shm_nattch;/* attachment count */
size_t shm_segsz; /* segment size */
struct pid *shm_cprid;/* creator PID */
struct pid *shm_lprid;/* last operator PID */
/* other kernel‑only fields */
};Lifecycle Operations
Creating a Segment – shmget
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);key : Integer identifier, often produced by ftok.
size : Must be a multiple of the system page size.
shmflg : Flags such as IPC_CREAT, IPC_EXCL, and permission bits (e.g., 0666).
On success the call returns a non‑negative shmid. The kernel allocates physical pages, creates shmid_ds and shmid_kernel objects, and sets the initial attachment count to zero.
Removing a Segment – shmctl with IPC_RMID
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);If cmd is IPC_RMID, the kernel marks the segment for deletion. The actual memory is reclaimed only when shm_nattch reaches zero.
Attaching – shmat
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg); shmid: Identifier returned by shmget. shmaddr: Desired virtual address (NULL lets the kernel choose). shmflg: 0 for read/write, SHM_RDONLY for read‑only.
Returns the attached address or (void *)‑1 on error.
Detaching – shmdt
#include <sys/shm.h>
int shmdt(const void *shmaddr);Removes the mapping and decrements the attachment count. If the segment was marked for removal and the count becomes zero, the kernel frees the physical pages.
Complete Example (Parent‑Child Communication)
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SHM_SIZE 1024 /* 1 KB */
int main() {
key_t key = ftok("testfile", 1);
if (key == -1) { perror("ftok"); exit(1); }
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0600);
if (shmid == -1) { perror("shmget"); exit(1); }
char *shm_ptr = (char *)shmat(shmid, NULL, 0);
if (shm_ptr == (char *)-1) { perror("shmat"); exit(1); }
pid_t pid = fork();
if (pid == -1) { perror("fork"); exit(1); }
if (pid == 0) { /* child */
printf("Child reading...
");
sleep(1); /* ensure parent wrote */
printf("Data: %s
", shm_ptr);
if (shmdt(shm_ptr) == -1) { perror("shmdt child"); exit(1); }
} else { /* parent */
printf("Parent writing...
");
strcpy(shm_ptr, "Hello from parent!");
wait(NULL);
if (shmdt(shm_ptr) == -1) { perror("shmdt parent"); exit(1); }
if (shmctl(shmid, IPC_RMID, NULL) == -1) { perror("shmctl"); exit(1); }
printf("Shared memory removed.
");
}
return 0;
}Steps:
Generate a key with ftok (requires an existing file such as testfile).
Create the segment with shmget (permissions 0600).
Map it into the process address space using shmat.
Fork a child; the child reads after a short delay, then detaches.
The parent writes, waits for the child, detaches, and finally removes the segment with shmctl.
Common Pitfalls and Solutions
ftok fails : Ensure the pathname exists and is accessible.
shmget fails : Verify permissions, that size is page‑aligned, and that the system has enough free memory.
shmat fails : Check that the returned shmid is valid and that the process has the requested access rights.
Data races : Shared memory provides no synchronization. Use semaphores, mutexes, or other IPC primitives to protect concurrent reads/writes.
Summary
Linux shared memory is implemented via kernel‑managed structures ( shmid_ds, ipc_perm, shmid_kernel) and page‑table mappings that allow multiple processes to access the same physical memory without copying. The API consists of shmget, ftok, shmat, shmdt, and shmctl. Proper handling of reference counts, permissions, and explicit synchronization is essential for safe and efficient inter‑process communication.
Deepin Linux
Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
