首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

進程間通信(IPC)深度解析:共享內存的 POSIX 與 System V 實現

     編輯:Java 綜合教學

為什麼選擇共享內存?

在管道、信號、消息隊列、Socket 等 IPC 方式中,共享內存速度最快。一旦內存區映射到進程地址空間,資料傳遞不再經過內核,極大降低複製開銷。但需注意:多進程並發讀寫必須配合同步機制(如信號量)保護關鍵區。

POSIX 共享內存:基於 mmap 的靈活方案

核心介面

  • shm_open / open + mmap 建立映射
  • munmap 解除映射
  • msync 刷新至磁碟
  • shm_unlink 移除物件

支援的檔案類型

  1. 普通磁碟檔案
  2. 裝置檔案(特殊裝置除外)
  3. 記憶體檔案(如 tmpfs 下的檔案)
  4. 匿名映射(MAP_ANON,適用於有親緣關係的進程)

匿名映射範例

mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);

flags 包含 MAP_ANON,fd 傳 -1 即可,無需打開檔案。

關鍵特性

  • 映射大小以頁面(預設 4096 位元組)對齊;檔案大小可透過 ftruncate 動態調整。
  • 適用於需持久化或嵌入式場景(避免頻繁寫入 Flash 導致壞塊)。

System V 共享內存:傳統高效的鍵值模型

核心介面

  • shmget 獲取/建立共享內存標識符
  • shmat 掛接至進程地址空間
  • shmdt 脫離掛接
  • shmctl 控制操作(如刪除 IPC_RMID)

系統限制(可透過 /proc/sys/kernel/ 或 ipcs 查看)

  • shmmax:單個段最大位元組數
  • shmmin:最小位元組數
  • shmmni:系統範圍內最大段數
  • shmseg:單進程最大掛接段數

特點對比

維度POSIX (mmap)System V
建立方式需開啟檔案鍵值直接建立
進程間同步需約定鍵或傳遞 fd統一 key 標識
讀寫速度略低通常更高
容量限制受檔案系統/記憶體限制受核心參數限制,不可過大

同步機制:信號量保護關鍵區

無論哪種方式,多進程讀寫都必須互斥。常用 POSIX 信號量:

sem_init(&mutex, 1, 1);  // 進程間共享
sem_wait(&mutex);        // 加鎖
sem_post(&mutex);        // 解鎖
// 編譯需鏈接 -lpthread

完整代碼範例

POSIX 寫端(建立並寫入)

#include <sys/mman.h> #include <fcntl.h> #include <semaphore.h>
#define FILE "/tmp/cluster_share"
struct Data { sem_t mutex; int arr[10]; } *ptr;
int fd = open(FILE, O_CREAT|O_RDWR|O_TRUNC, 0777);
lseek(fd, sizeof(struct Data)-1, SEEK_SET); write(fd, "", 1);
ptr = mmap(NULL, sizeof(*ptr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
sem_init(&ptr->mutex, 1, 1);
while(1) { sem_wait(&ptr->mutex); /* 寫入 */ sem_post(&ptr->mutex); sleep(1); }

POSIX 讀端(掛接並讀取)

int fd = open(FILE, O_RDWR);
ptr = mmap(NULL, sizeof(*ptr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
while(1) { sem_wait(&ptr->mutex); /* 讀取 */ sem_post(&ptr->mutex); sleep(1); }

System V 寫端

#include <sys/shm.h> #include <semaphore.h>
int shmid = shmget(12345, sizeof(struct Data), 0666|IPC_CREAT);
void *shm = shmat(shmid, 0, 0);
struct Data *ptr = (struct Data*)shm;
sem_init(&ptr->mutex, 1, 1);
while(1) { sem_wait(&ptr->mutex); /* 寫入 */ sem_post(&ptr->mutex); sleep(1); }

System V 讀端

int shmid = shmget(12345, sizeof(struct Data), 0666);
void *shm = shmat(shmid, 0, 0);
struct Data *ptr = (struct Data*)shm;
while(1) { sem_wait(&ptr->mutex); /* 讀取 */ sem_post(&ptr->mutex); sleep(1); }

總結建議

  • 新專案優先考慮 POSIX(標準化、支援 tmpfs、易於除錯)。
  • 舊系統維護或需極致吞吐量時,System V 仍是可靠選擇。
  • 切記:共享內存必須配合信號量/互斥鎖使用,否則會發生資料競爭。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved