首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Linux C 程式設計:共享記憶體進程間通訊實作範例

     編輯:關於C語言

共享記憶體 IPC 機制概述

共享記憶體是 Linux 系統中最底層、最高效的進程間通訊(IPC)機制。它允許兩個或多個進程映射同一塊物理記憶體區域,直接讀寫資料,無需核心複製,效能極佳。但缺乏內建同步機制,必須搭配信號量、互斥鎖等同步原語,避免競態條件導致資料混亂。

運作原理

  1. 一個進程呼叫 shmget() 建立或取得共享記憶體段
  2. 各進程呼叫 shmat() 將該段附加到自身虛擬位址空間
  3. 進程間直接透過指標讀寫共享區域
  4. 使用完畢呼叫 shmdt() 分離,最後由建立者呼叫 shmctl(IPC_RMID) 刪除

完整範例:雙進程資料傳遞

以下範例示範兩個獨立程式 b.c(寫入端)與 a.c(讀取端)透過共享記憶體交換字串。注意:為簡化示範,本範例未加入同步機制,實際執行時輸出會出現交錯混亂,請務必在正式專案中加入信號量同步。

寫入端程式:b.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;
}

讀取端程式:a.c

#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

執行結果說明

writer 執行畫面 reader 執行畫面

因無同步機制,reader 可能讀到 writer 正在寫入時的部分資料,導致輸出亂碼或重複。這正是共享記憶體「高效但不安全」的特性體現。

關鍵函數速查表

函數用途關鍵參數
shmget(key, size, flags)建立/取得共享記憶體 IDkey: 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 取得狀態

最佳實務建議

  • 必須搭配同步:使用 POSIX 信號量(sem_t)或 System V 信號量(semget/semop)保護關鍵區
  • 定義清晰協議:共享區建議包含「資料長度 + 資料內容」或環狀緩衝區結構
  • 錯誤處理:所有系統呼叫皆需檢查回傳值,善用 perror() 診斷
  • 資源清理:程式異常結束時應註冊 atexit() 或信號處理器確保 shmctl(IPC_RMID) 被呼叫
  • 權限設定:shmget 權限位建議 0600(僅擁有者讀寫)或 0660(群組共享)

延伸閱讀

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved