Linux shared memory lets two or more processes read and write the same block of RAM, with no copying through pipes or sockets in between. That makes it the fastest way for processes on one machine to talk. Below are two complete C programs, a writer and a reader, that compile and run as-is, plus the System V version, a POSIX vs System V comparison, and the cleanup commands you’ll need when a segment gets stuck.
I compiled and ran every example on this page on Ubuntu 24.04 with GCC 13. The output shown is the real output.
The Short Version
- New code: use POSIX shared memory,
shm_openplusmmap. It shows up as a file in/dev/shm. - Old code and tutorials use System V:
shmget,shmat,shmdt,shmctl. It still works fine. - Shared memory has no built-in locking. If more than one process writes, add a semaphore.
- Segments outlive your program. Always clean up with
shm_unlinkorshmctl(IPC_RMID).
Understanding Shared Memory
Normally every process has its own private memory. The kernel makes sure process A can’t see process B’s data. Shared memory is the deliberate exception: the kernel maps the same physical pages into both processes, so a write by one is instantly visible to the other.
Why Use Shared Memory
Speed. Pipes, sockets and message queues all copy data through the kernel. Shared memory doesn’t copy at all after setup. The tradeoff is that you’re now responsible for coordination, which is where most bugs come from.
POSIX vs System V Shared Memory
Linux has two APIs for the same idea. Here’s how they compare:
| POSIX | System V | |
|---|---|---|
| Create / open | shm_open() | shmget() |
| Attach | mmap() | shmat() |
| Detach | munmap() | shmdt() |
| Delete | shm_unlink() | shmctl(id, IPC_RMID, NULL) |
| Identified by | A name like /my_shm | A numeric key, usually from ftok() |
| Where you see it | ls /dev/shm | ipcs -m |
| Pick it for | New code | Existing code that already uses it |
My take: use POSIX for anything new. The API is file-like, which is easier to reason about, and you can inspect it with plain ls.
Getting Started with Linux Shared Memory (POSIX)
The writer creates a 4 KB shared segment, maps it into its own address space, and writes a string into it. Save it as writer.c:
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#define SHM_NAME "/ceos3c_demo"
#define SHM_SIZE 4096
int main(void) {
int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0600);
if (fd == -1) { perror("shm_open"); return 1; }
if (ftruncate(fd, SHM_SIZE) == -1) { perror("ftruncate"); return 1; }
char *mem = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mem == MAP_FAILED) { perror("mmap"); return 1; }
snprintf(mem, SHM_SIZE, "Hello from PID %d", getpid());
printf("Wrote: %s\n", mem);
munmap(mem, SHM_SIZE);
close(fd);
return 0;
}Code language: PHP (php)
Reading Shared Memory
The reader opens the same name read-only, maps it, prints what’s there, and then removes the segment. Save it as reader.c:
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#define SHM_NAME "/ceos3c_demo"
#define SHM_SIZE 4096
int main(void) {
int fd = shm_open(SHM_NAME, O_RDONLY, 0);
if (fd == -1) { perror("shm_open"); return 1; }
char *mem = mmap(NULL, SHM_SIZE, PROT_READ, MAP_SHARED, fd, 0);
if (mem == MAP_FAILED) { perror("mmap"); return 1; }
printf("Read: %s\n", mem);
munmap(mem, SHM_SIZE);
close(fd);
shm_unlink(SHM_NAME); /* remove it once we're done */
return 0;
}Code language: PHP (php)
Compile and Run
gcc -Wall -o writer writer.c
gcc -Wall -o reader reader.c
./writer
ls -l /dev/shm
./reader
Here’s the output on my test box:
$ ./writer
Wrote: Hello from PID 463
$ ls -l /dev/shm
-rw------- 1 root root 4096 Oct 5 15:47 ceos3c_demo
$ ./reader
Read: Hello from PID 463
$ ./reader
shm_open: No such file or directoryCode language: JavaScript (javascript)
The second ./reader fails on purpose. The first run called shm_unlink, so the segment is gone. That’s the cleanup working.
On older systems (glibc before 2.34) you’ll get an undefined reference to shm_open. Add -lrt to the gcc line to fix it.
The System V Version
Same idea with the older API. You’ll see this in a lot of existing code and university courses. Writer:
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 1024
int main(void) {
key_t key = ftok("/tmp", 'C');
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0600);
if (shmid == -1) { perror("shmget"); return 1; }
char *mem = shmat(shmid, NULL, 0);
if (mem == (char *) -1) { perror("shmat"); return 1; }
strcpy(mem, "Hello from System V shared memory");
printf("Wrote to segment %d\n", shmid);
shmdt(mem);
return 0;
}Code language: PHP (php)
Reader:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 1024
int main(void) {
key_t key = ftok("/tmp", 'C');
int shmid = shmget(key, SHM_SIZE, 0600);
if (shmid == -1) { perror("shmget"); return 1; }
char *mem = shmat(shmid, NULL, SHM_RDONLY);
if (mem == (char *) -1) { perror("shmat"); return 1; }
printf("Read: %s\n", mem);
shmdt(mem);
shmctl(shmid, IPC_RMID, NULL); /* delete the segment */
return 0;
}Code language: PHP (php)
$ ./sysv_writer
Wrote to segment 0
$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x43000035 0 root 600 1024 0
$ ./sysv_reader
Read: Hello from System V shared memoryCode language: JavaScript (javascript)
ftok("/tmp", 'C') turns a path and a character into a key both programs agree on. The path has to exist, and both processes must use the same path and character.
Key Things to Remember
Memory Management Tips
- Segments don’t disappear when your program exits. If nobody calls
shm_unlinkorIPC_RMID, they stay until reboot. - Use permissions like
0600unless other users really need access. - Shared memory counts as shared in
free -h, and on most systems/dev/shmis capped at half your RAM.
Keeping Things in Sync
The examples above are safe only because one process writes and then the other reads. If two processes write at the same time, you get torn, half-written data. The usual fix is a named POSIX semaphore around every access:
sem_t *lock = sem_open("/ceos3c_lock", O_CREAT, 0600, 1);
sem_wait(lock); /* take the lock */
/* read or write shared memory here */
sem_post(lock); /* release it */
sem_close(lock);Code language: JavaScript (javascript)
Remove it with sem_unlink("/ceos3c_lock") when you’re done, same as the memory segment.
Checking on Shared Memory
# POSIX segments
ls -l /dev/shm
# System V segments
ipcs -m
# details for one System V segment
ipcs -m -i <shmid>Code language: PHP (php)
Common Problems and Fixes
| Error | Cause | Fix |
|---|---|---|
shm_open: No such file or directory | Reader ran before the writer, or the segment was already unlinked | Run the writer first. Check ls /dev/shm |
shm_open: Permission denied | Created by another user with 0600 | Run as the same user, or create it with looser permissions |
undefined reference to shm_open | Old glibc | Link with -lrt |
shmget: Invalid argument | Segment exists with a smaller size than you asked for | Remove it with ipcrm -m <shmid> and recreate |
| Segments piling up | Programs crash before cleanup | rm /dev/shm/name for POSIX, ipcrm -m <shmid> for System V |
Real-World Uses
PostgreSQL keeps its shared buffer cache in shared memory. Chrome and Firefox use it to move data between their many processes. Audio and video pipelines use it to hand big buffers around without copying. If you’re moving lots of data between processes on one machine and a socket is too slow, this is the tool.
FAQ
Is shared memory faster than pipes?
Yes, for large data. Pipes copy every byte through the kernel. Shared memory copies nothing after setup. For small messages the difference rarely matters.
Where is shared memory stored in Linux?
In RAM. POSIX segments appear as files in /dev/shm, which is a tmpfs filesystem backed by memory, not disk.
Does shared memory survive a reboot?
No. It lives in RAM and is gone after a restart.
Making It Work Better
Start with the POSIX writer and reader above, add a semaphore the moment a second writer shows up, and always clean up. If you want the bigger picture of how Linux handles RAM, cache and swap, read my Linux memory management guide. The shm_overview man page is the reference.