shmget() is the first step in using System V shared memory. It either creates a new segment or opens an existing one, identified by a numeric key. It returns an integer ID (shmid) which is used in all subsequent operations on that segment.
Function Signature
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
/*
* key – IPC key identifying the segment (use ftok() or IPC_PRIVATE)
* size – size in bytes of the segment (rounded up to page size by kernel)
* shmflg – flags: permissions | IPC_CREAT | IPC_EXCL
*
* Returns: shmid (non-negative integer) on success, -1 on error
*/
| Parameter | Type | Meaning |
|---|---|---|
key |
key_t |
Numeric identifier. Two processes with the same key access the same segment. |
size |
size_t |
Bytes to allocate. Kernel rounds up to the nearest page boundary (usually 4096). |
shmflg |
int |
OR-combination of permission bits (e.g. 0660) and flag constants. |
Understanding key_t and ftok()
A key_t is just a 32-bit integer. It works like a “name” for the IPC object. Any two unrelated processes that use the same key value will get the same shared memory segment.
You can use a hardcoded number (not recommended for production), or use ftok() to generate one from a file path and a project ID:
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
/*
* Derives a key from the file's inode number + device number + proj_id.
* Both processes must use the same pathname AND proj_id to get the same key.
* The file must exist and both processes must have permission to stat it.
*
* Returns: key_t on success, (key_t)-1 on error
*/
/* Example: two processes generating the same key */
key_t key = ftok("/var/myapp/shm.token", 'S');
if (key == (key_t)-1) {
perror("ftok");
exit(1);
}
/* key is now a consistent value both processes can use */
int shmid = shmget(key, 4096, IPC_CREAT | 0660);
if (shmid == -1) {
perror("shmget");
exit(1);
}
printf("shmid = %d\n", shmid);
IPC_PRIVATE (value 0): Pass this as the key when you want the kernel to always create a brand-new segment with no shareable key. Useful for parent-child IPC via fork() since the child inherits the shmid.
/* IPC_PRIVATE — for parent-child via fork() */
int shmid = shmget(IPC_PRIVATE, 8192, IPC_CREAT | 0600);
if (shmid == -1) { perror("shmget"); exit(1); }
pid_t pid = fork();
if (pid == 0) {
/* child: inherits shmid, can call shmat() with it */
char *shm = shmat(shmid, NULL, 0);
printf("Child sees: %s\n", shm);
shmdt(shm);
exit(0);
}
/* parent: write something */
char *shm = shmat(shmid, NULL, 0);
strcpy(shm, "Hello child!");
wait(NULL);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
shmflg – Flags Explained
| Flag | Meaning |
|---|---|
IPC_CREAT |
Create segment if it doesn’t exist. If it exists, open it (no error). |
IPC_EXCL |
Used with IPC_CREAT — fail with EEXIST if segment already exists. Guarantees creation. |
0600 etc. |
Unix permission bits (octal). Controls who can attach or modify the segment. |
SHM_HUGETLB |
Use huge pages (2MB or 1GB). Reduces TLB pressure for very large segments. Needs CAP_IPC_LOCK. |
SHM_NORESERVE |
Do not reserve swap space for this segment. Risky — process may get SIGSEGV on write if swap is full. |
Size and Page Rounding
The kernel rounds the requested size up to a multiple of the system page size (typically 4096 bytes). If you request 3000 bytes, you actually get 4096. If you request 5000 bytes, you get 8192. The extra bytes are accessible but you should not rely on them being zeroed or having any particular content.
#include <unistd.h>
#include <stdio.h>
/* Get system page size at runtime */
long page_size = sysconf(_SC_PAGESIZE);
printf("Page size: %ld bytes\n", page_size);
/* Round up size manually before calling shmget */
size_t wanted = 3000;
size_t actual = (wanted + page_size - 1) & ~(page_size - 1);
printf("Requested: %zu, Will get: %zu\n", wanted, actual);
/* Output: Requested: 3000, Will get: 4096 */
Complete Two-Process Example
Server creates the segment, writes data. Client opens it and reads.
/* === server.c === */
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SHM_KEY 0x4321
#define SHM_SIZE 512
int main(void) {
/* Create segment — fail if already exists */
int shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0660);
if (shmid == -1) {
perror("shmget"); /* EEXIST if already running */
exit(1);
}
printf("Server: created shmid=%d\n", shmid);
/* Attach */
char *shm = (char *)shmat(shmid, NULL, 0);
if (shm == (char *)-1) { perror("shmat"); exit(1); }
/* Write a message */
snprintf(shm, SHM_SIZE, "Temperature: 36.5 C, Humidity: 72%%");
printf("Server: wrote data, waiting 10s...\n");
sleep(10); /* Let client read */
/* Cleanup */
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
printf("Server: deleted segment\n");
return 0;
}
/* gcc -o server server.c */
/* === client.c === */
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#define SHM_KEY 0x4321
#define SHM_SIZE 512
int main(void) {
/* Open existing segment — no IPC_CREAT */
int shmid = shmget(SHM_KEY, SHM_SIZE, 0);
if (shmid == -1) {
perror("shmget"); /* ENOENT if server not started yet */
exit(1);
}
printf("Client: opened shmid=%d\n", shmid);
/* Attach read-only — we are just reading */
char *shm = (char *)shmat(shmid, NULL, SHM_RDONLY);
if (shm == (char *)-1) { perror("shmat"); exit(1); }
printf("Client: read: %s\n", shm);
shmdt(shm);
return 0;
}
/* gcc -o client client.c
* Run: ./server & then ./client
*/
Common Errors from shmget()
| errno | Cause | Fix |
|---|---|---|
EEXIST |
IPC_CREAT|IPC_EXCL used but segment already exists | Delete old segment with ipcrm or shmctl(IPC_RMID) |
ENOENT |
No IPC_CREAT but segment doesn’t exist | Start server first |
EINVAL |
Size smaller than SHMMIN or larger than SHMMAX, or size 0 | Check /proc/sys/kernel/shmmax |
ENOMEM |
Not enough RAM/swap | Reduce size or free memory |
ENOSPC |
Max number of segments (SHMMNI) reached | Run ipcs -m to find and delete leaked segments |
EACCES |
Permission denied on existing segment | Check segment permissions with ipcs -m |
Useful shell commands for debugging:
# List all shared memory segments
ipcs -m
# Delete a specific segment by shmid
ipcrm -m <shmid>
# Check system limits
cat /proc/sys/kernel/shmmax # max segment size in bytes
cat /proc/sys/kernel/shmall # max total pages of shared memory
cat /proc/sys/kernel/shmmni # max number of segments
Interview Questions
IPC_CREAT alone opens an existing segment if one with that key already exists, or creates it if it doesn’t — essentially an “open or create” operation. Adding IPC_EXCL makes it a strict create — it fails with EEXIST if the segment already exists. Use IPC_EXCL in server startup to guarantee you’re starting with a fresh, uninitialized segment, not accidentally reusing stale data.
It returns a non-negative integer called the shmid (shared memory identifier). This is the kernel’s internal ID for the segment. All subsequent operations — shmat(), shmdt(), shmctl() — take the shmid as their first argument. The shmid is local to the machine and changes across reboots or segment recreation.
ftok() generates a key_t by combining the file’s inode number, device number, and the supplied proj_id byte. Its limitation is that if the file is deleted and recreated, its inode number changes, producing a different key — even if the path looks the same. Also, inode number collisions can theoretically produce the same key for different files. For robust code, use a hardcoded unique key or a proper namespace mechanism.
If you’re opening an existing segment (no IPC_CREAT), passing size=0 is fine — the kernel ignores the size and returns the existing segment’s ID. If you’re creating a new segment, size=0 causes EINVAL because you must specify a positive size.
System V shared memory persists until explicitly deleted. If a process crashes before calling shmctl(IPC_RMID), the segment leaks. You can clean up with: ipcs -m to list all segments, then ipcrm -m <shmid> to remove each one. In production code, install a signal handler for SIGTERM/SIGINT that calls shmctl(IPC_RMID) before exiting.
EmbeddedPathashala.com | Free Embedded & Linux Tutorials
