共享內存SHM
文章目錄
- 共享內存SHM
- 1. 基本概念
- 2. 函數接口
- 2.1 創建或打開SHM對象
- 2.2 映射 / 解除映射SHM對象
- 2.3 其余操作
- 2.4示例代碼
1. 基本概念
共享內存,顧名思義,就是通過不同進程共享一段相同的內存來達到通信的目的,由于SHM對象不再交由內核托管,因此共享內存SHM對象是眾多IPC方式最高效的一種方式,但也因為這個原因,SHM一般不能單獨使用,而需要配合諸如互斥鎖、信號量等協同機制使用。
2. 函數接口
使用共享內存的一般步驟是:
- 獲取共享內存對象的ID
- 將共享內存映射至本進程虛擬內存空間的某個區域
- 當不再使用時,解除映射關系
- 當沒有進程再需要這塊共享內存時,刪除它。
下面來詳細介紹這些函數接口的用法。
2.1 創建或打開SHM對象
與消息隊列類似,SHM對象的創建或打開也需要一個唯一的鍵值標識,并且需要指定內存的大小尺寸,具體接口如下:
#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
接口說明:
- 返回值:SHM對象ID
- 參數key:SHM對象鍵值
- 參數size:共享內存大小
- 參數shmflg:創建模式和權限
- IPC_CREAT:如果key對應的共享內存不存在,則創建SHM對象
- IPC_EXCL:如果該key對應的共享內存已存在,則報錯
- 權限與文件創建open類似,用八進制表示
示例代碼:
int main(void)
{key_t key = ftok(".", 1);int shmid;// 創建或打開一個大小為1024自己的SHM對象,獲取其IDshmid = shmget(key, 1024, IPC_CREAT|0666);if(shmid < 0){perror("創建SHM對象失敗");}// ...return 0;
}
2.2 映射 / 解除映射SHM對象
有了SHM對象的ID之后,必須先將其映射到用戶進程的內存空間之后方可使用,映射接口如下:
#include <sys/types.h>
#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr/*一般為NULL*/, int shmflg);
接口說明:
- 功能:
- 將指定的共享內存,映射到本進程內存空間
- 參數:
- shmid:指定的共享內存的ID
- shmaddr:指定映射后的地址,因為是虛擬地址,分配的原則要兼顧諸如段對齊、權限分配等問題,因此用戶進程是無法指定的,只能由系統自動分配,因此此參數一般為NULL,表示交由系統來自動分配。
- shmflg:可選項
- 0:默認,代表共享內存可讀可寫。
- SHM_RDONLY:代表共享內存只讀。
- 返回值:
- 共享內存映射后的虛擬地址入口。
正確映射之后,命令ipcs -m查看SHM對象時,可從nattch列中看到已映射進程個數:
aidevelop@aidevelop-vm:~$ ipcs -m------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 688132 aidevelop 600 67108864 2 dest
0x00000000 688137 aidevelop 600 524288 2 dest
0x00000000 688138 aidevelop 600 524288 2 dest
0x00000000 688139 aidevelop 600 4389528 2 dest
0x00000000 688142 aidevelop 600 524288 2 dest
0x5101374a 20 aidevelop 600 1024 1
使用完SHM對象后,需要將其跟進程解除關聯關系,即解除映射,函數接口如下:
#include <sys/types.h>
#include <sys/shm.h>int shmdt(const void *shmaddr);
該函數接口非常簡單,參數就是從 shmat() 返回的SHM對象的入口指針。
2.3 其余操作
與其他IPC對象一樣,共享內存也有一個control函數,可用于設置SHM對象屬性信息、獲取SHM屬性信息、刪除SHM對象等其余操作,接口如下:
#include <sys/ipc.h>
#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);
接口說明:
- shmid:指定的共享內存的ID
- cmd:一些命令字
- IPC_STAT:獲取共享內存 的一些信息,放入shmid_ds{ }中
- IPC_SET:將 buf 中指定的信息,設置到本共享內存中
- IPC_RMID:刪除指定的共享內存,此時第三個參數 buf 將被忽略
- buf:用來存放共享內存信息的結構體
用的較多的就是刪除SHM對象,示例代碼如下:
shmctl(shmid, IPC_RMID, NULL);
2.4示例代碼
int main(int argc,char *argv[])
{key_t key = ftok(".",1);int shmid = shmget(key, SHMSIZE, IPC_CREAT | 0666);char *addr1 = shmat(shmid,NULL,0);bzero(addr1,SHMSIZE);fgets(addr1, SHMSIZE,stdin);shmdt(addr1);return 0;
}
int main(int argc,char *argv[])
{key_t key = ftok(".",1);int shmid = shmget(key, SHMSIZE, IPC_CREAT | 0666);char *addr2 = shmat(shmid,NULL,0);printf("from Jack : %s",addr2);shmdt(addr2);return 0;
}