共享記憶體:最快的 IPC(shared memory)
其他每一種 IPC 都在複製位元組:傳送方把資料交給核心,核心再交一份副本給接收方。共享記憶體徹底去掉了複製。核心安排同一批實體 RAM 分頁同時出現在兩個行程的定址空間裡。於是當一個行程把一個數字寫進那塊區域,另一個行程瞬間就看到,因為它們看的就是同一批位元組。這是兩個人在同一塊實體白板上書寫,而不是互相郵寄自己白板的照片。
設定它有兩種常見方式。較舊的 System V 風格:shmget() 以一個數字鍵建立或尋找一個共享區段,shmat() 把它接進你的定址空間某個指標處。POSIX/現代風格:shm_open() 給你一個類似檔案描述符的把手指向一個具名共享物件,你用 ftruncate() 設定它的大小,再用 mmap() 把它映射進記憶體。無論哪種方式,結果都一樣:一塊記憶體,比方 1 MiB,兩個行程都能透過普通指標 char *p 讀寫它,每次存取不需系統呼叫。因為一旦映射好就不再經過核心,共享記憶體是最快的 IPC。
但這速度伴隨著定義它的那個陷阱:核心不再居中協調每次存取,所以它不給你任何同步。若兩個行程同時寫同一個位置,或一個在讀而另一個正寫到一半,你會得到資料競爭與垃圾——和兩個執行緒共享記憶體完全相同的危險。你必須自己加上協調:放在共享記憶體裡的互斥鎖或號誌,或原子操作。所以共享記憶體不是「簡單又快的 IPC」——它是「原始的快速記憶體,外加一個現在歸你管的同步問題」。當你要搬大量資料且能管好上鎖時用它;只想要簡單、安全的訊息傳遞時,去拿管線或通訊端。
int fd = shm_open("/buf", O_CREAT|O_RDWR, 0600); ftruncate(fd, 4096); int *shared = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); shared[0] = 42; /* 另一個映射「/buf」的行程不必複製就看到 42 */
在兩個行程裡以 MAP_SHARED 映射同一個物件,一次普通指標寫入兩邊都看得到——瞬間,且未同步。
共享記憶體給你速度卻不給你安全:核心不會把存取序列化,所以並行寫入就是一種資料競爭,跟執行緒共享記憶體一模一樣。你必須自己加上互斥鎖、號誌或原子操作。