Linux進程通信 | 共享內存
一、共享內存是什么
在Linux系統中,共享內存是一種IPC(進程間通信)方式,它可以讓多個進程在物理內存中共享一段內存區域。
這種共享內存區域被映射到多個進程的虛擬地址空間中,使得多個進程可以直接訪問同一段物理內存區域中的數據,從而實現進程間的高速數據交換和通信。
二、共享內存的原理
共享內存基于內核的支持。在共享內存中,內核維護了一塊物理內存區域,并將其映射到多個進程的虛擬地址空間中。每個進程都可以使用指針來訪問共享內存區域中的數據,就像它們訪問自己的內存一樣。
三、共享內存的使用方法
相關函數介紹
shmget函數
int shmget(key_t key, size_t size, int shmflg);
用于創建或打開一個共享內存區段,具體參數如下:
| 參數 | 類型 | 說明 |
|---|---|---|
key |
key_t |
共享內存區段的關鍵字,用于在多個進程間標識同一個共享內存區段。 |
size |
size_t |
共享內存區段的大小,以字節為單位。 |
shmflg |
int |
共享內存區段的訪問權限和行為屬性。 |
函數返回值為共享內存區段的標識符 shmid,用于標識已創建或已打開的共享內存區段。
shmat函數
void *shmat(int shmid, const void *shmaddr, int shmflg);
用于將共享內存區段連接到當前進程的地址空間,具體參數如下:
| 參數 | 類型 | 說明 |
|---|---|---|
shmid |
int |
共享內存區段的標識符,用于標識已創建或已打開的共享內存區段。 |
shmaddr |
const void* |
共享內存區段連接到當前進程地址空間的起始地址,如果為 NULL,則由系統自動選擇一個地址。 |
shmflg |
int |
標志參數,指定共享內存區段的訪問權限和行為屬性。 |
函數返回值為共享內存區段連接到當前進程地址空間的起始地址,即指向共享內存區段的指針。
shmdt函數
int shmdt(const void *shmaddr);
用于斷開進程與共享內存區段的連接,具體參數如下:
| 參數 | 類型 | 說明 |
|---|---|---|
shmaddr |
const void* |
共享內存區段連接到當前進程地址空間的起始地址。 |
函數返回值為 0 表示成功,-1 表示失敗。
shmctl函數
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
用于控制共享內存區段的行為,如刪除、獲取、設置共享內存區段的屬性等,具體參數如下:
| 參數 | 類型 | 說明 |
|---|---|---|
shmid |
int |
共享內存區段的標識符,用于標識已創建或已打開的共享內存區段。 |
cmd |
int |
控制命令,指定對共享內存區段的操作類型。 |
buf |
struct shmid_ds* |
指向共享內存區段屬性結構體的指針,用于獲取或設置共享內存區段的屬性。 |
常用的cmd參數包括:
- IPC_STAT:獲取共享內存的狀態信息,并將該信息存儲在
buf參數指向的結構體中。 - IPC_SET:設置共享內存的狀態信息,
buf參數指向要設置的新值。 - IPC_RMID:刪除共享內存。
函數返回值為操作成功返回 0,失敗返回 -1。
實例演示
以下是一個示例代碼,其中一個程序用于寫入共享內存,另一個程序用于讀取共享內存。
寫入程序
/* write.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024
int main()
{
int shmid;
char *shmaddr;
char write_buf[SHM_SIZE];
// 創建共享內存段
shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
exit(EXIT_FAILURE);
}
// 將共享內存段連接到當前進程
shmaddr = (char*)shmat(shmid, 0, 0);
if (shmaddr == (void*)-1) {
perror("shmat failed");
exit(EXIT_FAILURE);
}
// 從標準輸入讀取數據并將其寫入共享內存
while(1) {
fgets(write_buf, SHM_SIZE, stdin);
strncpy(shmaddr, write_buf, SHM_SIZE);
if (strncmp(write_buf, "exit", 4) == 0) {
break;
}
}
// 斷開共享內存連接
if (shmdt(shmaddr) == -1) {
perror("shmdt failed");
exit(EXIT_FAILURE);
}
// 刪除共享內存段
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl failed");
exit(EXIT_FAILURE);
}
printf("write exit\n");
return 0;
}
讀取程序
/* read.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024
int main()
{
int shmid;
char *shmaddr;
char read_buf[SHM_SIZE];
// 獲取共享內存段
shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
exit(EXIT_FAILURE);
}
// 將共享內存段連接到當前進程
shmaddr = (char*)shmat(shmid, 0, 0);
if (shmaddr == (void*)-1) {
perror("shmat failed");
exit(EXIT_FAILURE);
}
// 從共享內存讀取數據并輸出到標準輸出
while(1) {
strncpy(read_buf, shmaddr, SHM_SIZE);
printf("Received message: %s\n", read_buf);
if (strncmp(read_buf, "exit", 4) == 0) {
printf("Received exit\n");
break;
}
sleep(1);
}
// 斷開共享內存連接
if (shmdt(shmaddr) == -1) {
perror("shmdt failed");
exit(EXIT_FAILURE);
}
printf("read exit\n");
return 0;
}
- 編譯這兩個程序
gcc -o write write.c
gcc -o read read.c
在一個終端窗口中運行write, 輸入消息,在另一個終端窗口中運行read,查看消息。
要退出程序,則在運行write的終端窗口中鍵入"exit",效果如下:

四、 共享內存的注意事項
- 使用共享內存需要注意以下幾點:
- 同步問題:由于多個進程可以同時訪問共享內存,因此必須要使用同步機制來保證數據的一致性和正確性。
- 內存泄漏:如果一個進程崩潰或者沒有及時解除共享內存映射,就有可能導致內存泄漏的問題。
- 安全問題:共享內存是多個進程共享的,因此必須要注意數據的安全性和隱私性,避免敏感數據泄露。
五、 共享內存的使用技巧
- 以下是一些共享內存的使用技巧:
- 分配內存時使用
shmget()系統調用中的IPC_PRIVATE標記,可以確保共享內存的鍵值在系統中是唯一的,避免沖突和安全問題。 - 在讀寫共享內存之前,使用信號量或互斥鎖等同步機制來保證數據的一致性和正確性。
- 在使用共享內存時,可以將共享內存區域按照固定大小進行分塊,避免多個進程同時訪問同一塊內存區域的沖突。
小結
共享內存是一種高效、靈活、方便的進程間通信方式,可以用于在多個進程之間共享大量數據。
使用共享內存需要注意同步、安全和內存泄漏等問題,可以使用信號量、互斥鎖等同步機制來保證數據的正確性。
以上,如果覺得對你有幫助,點個贊再走吧,這樣@知微之見也有更新下去的動力!
也歡迎私信我,一起交流!

浙公網安備 33010602011771號