共享記憶體是 Linux 系統中最底層、最高效的進程間通訊(IPC)機制。它允許兩個或多個進程映射同一塊物理記憶體區域,直接讀寫資料,無需核心複製,效能極佳。但缺乏內建同步機制,必須搭配信號量、互斥鎖等同步原語,避免競態條件導致資料混亂。
shmget() 建立或取得共享記憶體段shmat() 將該段附加到自身虛擬位址空間shmdt() 分離,最後由建立者呼叫 shmctl(IPC_RMID) 刪除以下範例示範兩個獨立程式 b.c(寫入端)與 a.c(讀取端)透過共享記憶體交換字串。注意:為簡化示範,本範例未加入同步機制,實際執行時輸出會出現交錯混亂,請務必在正式專案中加入信號量同步。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#define BUF_SIZE 1024
#define MYKEY 25
int main() {
int shmid;
char *shmptr;
// 建立/取得共享記憶體
if ((shmid = shmget(MYKEY, BUF_SIZE, IPC_CREAT | 0666)) == -1) {
perror("shmget error");
exit(1);
}
// 附加到進程位址空間
if ((shmptr = shmat(shmid, 0, 0)) == (void *)-1) {
perror("shmat error");
exit(1);
}
while (1) {
printf("input: ");
if (scanf("%1023s", shmptr) != 1) break; // 防緩衝區溢位
}
shmdt(shmptr);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#define BUF_SIZE 1024
#define MYKEY 25
int main() {
int shmid;
char *shmptr;
if ((shmid = shmget(MYKEY, BUF_SIZE, IPC_CREAT | 0666)) == -1) {
perror("shmget error");
exit(1);
}
if ((shmptr = shmat(shmid, 0, 0)) == (void *)-1) {
perror("shmat error");
exit(1);
}
while (1) {
printf("string: %s\n", shmptr);
sleep(3);
}
shmdt(shmptr);
return 0;
}
# 編譯兩支程式
$ gcc -o writer b.c
$ gcc -o reader a.c
# 開啟兩個終端機視窗
# 終端機 1 執行寫入端
$ ./writer
# 終端機 2 執行讀取端
$ ./reader

因無同步機制,reader 可能讀到 writer 正在寫入時的部分資料,導致輸出亂碼或重複。這正是共享記憶體「高效但不安全」的特性體現。
| 函數 | 用途 | 關鍵參數 |
|---|---|---|
shmget(key, size, flags) | 建立/取得共享記憶體 ID | key: IPC 鍵值;size: 位元組大小;flags: IPC_CREAT | 權限 |
shmat(shmid, addr, flag) | 附加共享記憶體到進程空間 | addr: 通常為 0 由核心決定;flag: SHM_RDONLY 唯讀 |
shmdt(shmaddr) | 分離共享記憶體 | shmaddr: shmat 回傳位址 |
shmctl(shmid, cmd, buf) | 控制共享記憶體 | cmd: IPC_RMID 刪除、IPC_STAT 取得狀態 |
sem_t)或 System V 信號量(semget/semop)保護關鍵區perror() 診斷atexit() 或信號處理器確保 shmctl(IPC_RMID) 被呼叫shmget 權限位建議 0600(僅擁有者讀寫)或 0660(群組共享)