共享內存是系統為多進程通訊(IPC)預留的一塊物理內存區域,允許不相關進程通過映射同一物理頁實現高速數據交換。內核通過 /proc/sys/kernel/ 下的參數(如 shmmax、shmmni)限制資源配額,通常無需手動調整。
key_t ftok(const char *pathname, int proj_id);
pathname:必須存在且可訪問的文件路徑proj_id:1-255 之間的整數(常用 ASCII 字符)key_t,失敗返回 -1也可直接定義固定鍵值:#define IPCKEY 0x344378,避免跨主機路徑不一致問題。
int shmget(key_t key, size_t size, int shmflg);
key:IPC 鍵值,父子進程可用 IPC_PRIVATEsize:段大小(字節)shmflg:權限 | 標志位(IPC_CREAT 創建,IPC_EXCL 獨佔)權限位示例:0640(擁有者讀寫、組讀、其他無)。關鍵陷阱:
shmflg 必須包含權限位,否則返回地址全為 0xFFFFFFFF 不可用。IPC_CREAT,否則在刪除重建場景下會導致後續創建失敗,需更換 key。void *shmat(int shmid, const void *shmaddr, int shmflg);
shmaddr=0:內核自動選擇地址(推薦)shmflg=SHM_RDONLY:只讀掛接,否則讀寫(void*)-1int shmdt(const void *shmaddr);
僅斷開當前進程映射,不刪除共享內存段本身。成功返回 0。
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
IPC_STAT:獲取狀態到 bufIPC_SET:從 buf 設置狀態IPC_RMID:標記刪除(最後一個進程分離後真正釋放)#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define IPCKEY 0x366378
typedef struct {
char agen[10];
unsigned char file_no;
} st_setting;
int main() {
int shm_id;
st_setting *p_setting;
// 1. 嘗試獲取並清理舊段
shm_id = shmget(IPCKEY, 1028, 0640);
if (shm_id != -1) {
p_setting = (st_setting*)shmat(shm_id, NULL, 0);
if (p_setting != (void*)-1) {
shmdt(p_setting);
shmctl(shm_id, IPC_RMID, 0);
}
}
// 2. 創建新段(獨佔模式)
shm_id = shmget(IPCKEY, 1028, 0640 | IPC_CREAT | IPC_EXCL);
if (shm_id == -1) { perror("shmget"); return -1; }
// 3. 掛接並讀寫
p_setting = (st_setting*)shmat(shm_id, NULL, 0);
strncpy(p_setting->agen, "jinyh", 10);
p_setting->file_no = 1;
printf("agen:%s\nfile_no:%d\n", p_setting->agen, p_setting->file_no);
system("ipcs -m"); // 查看 nattch=1
// 4. 分離
shmdt(p_setting);
system("ipcs -m"); // 查看 nattch=0
// 5. 刪除段
shmctl(shm_id, IPC_RMID, NULL);
return 0;
}
ipcs -m:查看共享內存段信息(nattch 為掛接進程數)ipcrm -m <shmid>:強制刪除段最佳實踐:程序退出前務必調用 shmctl(IPC_RMID) 或確保有清理機制,否則段將長期駐留內存。
| 現象 | 原因 | 對策 |
|---|---|---|
| shmget 返回 -1 | 權限不足、key 衝突、超過系統限額 | 檢查 shmflg 權限位、更換 key、調整 /proc/sys/kernel/shmmax |
| shmat 返回 -1 | 地址空間不足、無效 shmid | 使用 shmaddr=0 讓內核選址、驗證 shmid 有效性 |
| 數據不同步 | 多進程並發無同步機制 | 配合信號量(semaphore)或互斥鎖保護關鍵區 |
| 段無法刪除 | 仍有進程掛接(nattch>0) | 確保所有進程 shmdt 後再 IPC_RMID |