Introduction
Shared memory is the fastest form of interprocess communication because, once set up, it removes the kernel from the data path entirely: two or more processes map the same physical memory frames into their respective virtual address spaces and thereafter read and write that region with ordinary CPU load/store instructions, exactly as if it were private memory. There is no copying through the kernel and no system call per access, which is why shared memory dramatically outperforms pipes or message queues for large or frequent data transfers. The price of that speed is that the operating system does nothing to serialize concurrent access to the shared region -- if two processes write to it simultaneously without coordination, the result is a race condition, so applications must pair shared memory with an explicit synchronization primitive such as a semaphore or mutex.
Cricket analogy: Two commentators sharing the same live scoreboard feed directly, rather than relaying updates through a runner between the press box and the ground, update instantly with no delay -- but if both edit the same total at once without coordinating, they'll produce conflicting scores, so they need an agreed hand-signal protocol (a mutex) to avoid stepping on each other.
Syntax
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(void) {
key_t key = ftok("/tmp", 'S');
int shmid = shmget(key, 4096, IPC_CREAT | 0666);
char *addr = shmat(shmid, NULL, 0); /* attach to address space */
/* ... read/write addr directly ... */
shmdt(addr); /* detach when done */
shmctl(shmid, IPC_RMID, NULL); /* mark segment for removal */
return 0;
}Explanation
shmget() asks the kernel to create or locate a shared memory segment identified by a key, returning an identifier. shmat() maps that segment into the calling process's virtual address space and returns a pointer usable directly in C code; from that point on there is no distinction between accessing this memory and accessing any other heap or stack memory in terms of CPU cost. Because multiple processes can attach the same segment and race to read/write it, correct programs must add a separate synchronization mechanism -- typically a POSIX or System V semaphore (sem_open()/sem_wait()/sem_post(), or semget()/semop()) -- to enforce mutual exclusion or coordinate producer/consumer access, since the shared memory API itself provides no locking, ordering, or notification guarantees.
Cricket analogy: Booking a shared scoreboard slot (shmget) reserves the display and returns its ID; hanging the actual scoreboard on the wall (shmat) makes it directly writable by any scorer with no extra step per update -- but because multiple scorers can now write to it freely, they still need an agreed signal system (a semaphore) to avoid two people updating the same total at once.
Example
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>
int main(void) {
int shmid = shmget(IPC_PRIVATE, 128, IPC_CREAT | 0666);
char *shm = shmat(shmid, NULL, 0);
sem_unlink("/demo_sem");
sem_t *sem = sem_open("/demo_sem", O_CREAT, 0666, 0);
pid_t pid = fork();
if (pid == 0) {
strcpy(shm, "data from child");
sem_post(sem); /* signal parent: data ready */
_exit(0);
} else {
sem_wait(sem); /* block until child signals */
printf("parent read: %s\n", shm);
wait(NULL);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
sem_close(sem);
sem_unlink("/demo_sem");
}
return 0;
}Analysis
Without the semaphore in this example, the parent could read shm before the child finishes writing to it, producing garbage or partial data -- a textbook race condition, because shmat() and raw memory access give no ordering guarantee whatsoever. The sem_wait()/sem_post() pair enforces a happens-before relationship: the parent only proceeds past sem_wait() once the child has called sem_post(), guaranteeing the write is complete and visible before the read. This illustrates the central lesson of shared memory: it delivers maximum throughput precisely because the kernel stays out of the way, but that same absence of kernel mediation means every ordering or exclusion guarantee an application needs must be built explicitly using semaphores, mutexes, or another synchronization primitive.
Cricket analogy: Without a hand-signal protocol, the second scorer could read the running total before the first scorer finishes updating it for a boundary, publishing a half-updated score -- a textbook race condition; a 'wait for my nod' signal (sem_wait/sem_post) guarantees the second scorer only reads after the first has fully finished writing.
Key Takeaways
- Shared memory maps the same physical memory into multiple processes' address spaces; after mapping, access is via direct CPU instructions with no per-access system call, making it the fastest IPC mechanism.
- shmget() creates/locates a segment, shmat() attaches it into the process address space, shmdt() detaches, and shmctl(IPC_RMID) removes it.
- The OS provides no automatic serialization of concurrent shared memory access; simultaneous unsynchronized writes cause race conditions.
- Shared memory must be paired with an explicit synchronization primitive, such as a semaphore or mutex, to coordinate safe access.
Practice what you learned
1. Why is shared memory generally the fastest IPC mechanism?
2. What does the operating system guarantee about concurrent access to a shared memory segment by multiple processes?
3. Which system call maps an existing shared memory segment into a process's address space?
4. In the parent/child shared memory example, what would likely happen if sem_wait()/sem_post() were removed?
Was this page helpful?
You May Also Like
Interprocess Communication
How independent processes with separate address spaces exchange data and coordinate using OS-provided IPC mechanisms.
Pipes and Message Queues
Distinguishing anonymous pipes, named pipes (FIFOs), and message queues as message-passing IPC mechanisms.
Mutex and Semaphores
Compare mutexes and binary/counting semaphores as tools for enforcing mutual exclusion and coordinating threads.