Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 共享內存完整指南:API 詳解、示例代碼與避坑指南

編輯:Linux 教學

共享內存機制概述

共享內存是系統為多進程通訊(IPC)預留的一塊物理內存區域,允許不相關進程通過映射同一物理頁實現高速數據交換。內核通過 /proc/sys/kernel/ 下的參數(如 shmmax、shmmni)限制資源配額,通常無需手動調整。

核心 API 詳解

1. ftok() — 生成 IPC 鍵值

key_t ftok(const char *pathname, int proj_id);
  • pathname:必須存在且可訪問的文件路徑
  • proj_id:1-255 之間的整數(常用 ASCII 字符)
  • 返回 key_t,失敗返回 -1

也可直接定義固定鍵值:#define IPCKEY 0x344378,避免跨主機路徑不一致問題。

2. shmget() — 獲取/創建共享內存段

int shmget(key_t key, size_t size, int shmflg);
  • key:IPC 鍵值,父子進程可用 IPC_PRIVATE
  • size:段大小(字節)
  • shmflg:權限 | 標志位(IPC_CREAT 創建,IPC_EXCL 獨佔)

權限位示例:0640(擁有者讀寫、組讀、其他無)。關鍵陷阱:

  • 創建時 shmflg 必須包含權限位,否則返回地址全為 0xFFFFFFFF 不可用。
  • 獲取既有段時勿加 IPC_CREAT,否則在刪除重建場景下會導致後續創建失敗,需更換 key。

3. shmat() — 掛接到進程地址空間

void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmaddr=0:內核自動選擇地址(推薦)
  • shmflg=SHM_RDONLY:只讀掛接,否則讀寫
  • 成功返回掛接地址,失敗返回 (void*)-1

4. shmdt() — 分離掛接

int shmdt(const void *shmaddr);

僅斷開當前進程映射,不刪除共享內存段本身。成功返回 0。

5. shmctl() — 控制命令

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • IPC_STAT:獲取狀態到 buf
  • IPC_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
Copyright © Windows教程網 All Rights Reserved