共享內存的基本概念
共享內存區是最快的IPC形式。一旦這樣的內存映射到共享它的進程的地址空間,這些進程間數據傳遞不再涉及到內核,換句話說是進程不再通過執行進入內核的系統調用來傳遞彼此的數據。
下圖是共享內存示意圖:
下圖是用管道或者消息隊列傳遞數據示意圖:
內核為每個IPC對象維護一個數據結構
下圖是用共享內存傳遞數據示意圖:
System V共享內存API:
首先了解一下下面結構體
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};
共享內存函數
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
下面依次介紹一下上述函數的一些使用方法
shmget函數
功能:用來創建共享內存
原型:intshmget(key_t key, size_t size, intshmflg);
參數:
key:這個共享內存段名字
size:共享內存大小
shmflg:由九個權限標志構成,它們的用法和創建文件時使用的mode模式標志是一樣的
返回值:成功返回一個非負整數,即該共享內存段的標識碼;失敗返回-1
shmat函數
功能:將共享內存段連接到進程地址空間
原型:void *shmat(intshmid, const void *shmaddr, intshmflg);
參數:
shmid: 共享內存標識
shmaddr:指定連接的地址
shmflg:它的兩個可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一個指針,指向共享內存第一個節;失敗返回-1
shmaddr為NULL,核心自動選擇一個地址
shmaddr不為NULL且shmflg無SHM_RND標記,則以shmaddr為連接地址。
shmaddr不為NULL且shmflg設置了SHM_RND標記,則連接的地址會自動向下調整為SHMLBA的整數倍。公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示連接操作用來只讀共享內存
shmdt函數
功能:將共享內存段與當前進程脫離
原型:intshmdt(const void *shmaddr);
參數:
shmaddr: 由shmat所返回的指針
返回值:成功返回0;失敗返回-1
注意:將共享內存段與當前進程脫離不等於刪除共享內存段
shmctl函數
功能:用於控制共享內存
原型:intshmctl(intshmid, intcmd, structshmid_ds *buf);
參數:
shmid:由shmget返回的共享內存標識碼
cmd:將要采取的動作(有三個可取值)
buf:指向一個保存着共享內存的模式狀態和訪問權限的數據結構
返回值:成功返回0;失敗返回-1
生成共享內存示例代碼:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include <sys/ipc.h> 4 #include <sys/shm.h> 5 #include<string.h> 6 #include<errno.h> 7 8 typedef struct _Teacher 9 { 10 char name[64]; 11 int age; 12 }Teacher; 13 14 int main(int argc, char *argv[]) 15 { 16 int ret = 0; 17 int shmid; 18 //創建共享內存 ,相當於打開文件,文件不存在則創建 19 shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT | 0666); 20 if (shmid == -1) 21 { 22 perror("shmget err"); 23 return errno; 24 } 25 printf("shmid:%d \n", shmid); 26 Teacher *p = NULL; 27 //將共享內存段連接到進程地址空間 28 p = shmat(shmid, NULL, 0);//第二個參數shmaddr為NULL,核心自動選擇一個地址 29 if (p == (void *)-1 ) 30 { 31 perror("shmget err"); 32 return errno; 33 } 34 strcpy(p->name, "aaaa"); 35 p->age = 33; 36 //將共享內存段與當前進程脫離 37 shmdt(p); 38 39 printf("鍵入1 刪除共享內存,其他不刪除\n"); 40 41 int num; 42 scanf("%d", &num); 43 if (num == 1) 44 { 45 //用於控制共享內存 46 ret = shmctl(shmid, IPC_RMID, NULL);//IPC_RMID為刪除內存段 47 if (ret < 0) 48 { 49 perror("rmerrr\n"); 50 } 51 } 52 53 return 0; 54 }
執行程序過程及測試步驟如下圖:
獲取共享內存示例代碼:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include <sys/ipc.h> 4 #include <sys/shm.h> 5 #include<string.h> 6 #include<errno.h> 7 8 typedef struct _Teacher 9 { 10 char name[64]; 11 int age; 12 }Teacher; 13 14 int main(int argc, char *argv[]) 15 { 16 int ret = 0; 17 int shmid; 18 //shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT |IPC_EXCL | 0666); 19 //打開獲取共享內存 20 shmid = shmget(0x2234, 0, 0); 21 if (shmid == -1) 22 { 23 perror("shmget err"); 24 return errno; 25 } 26 printf("shmid:%d \n", shmid); 27 Teacher *p = NULL; 28 //將共享內存段連接到進程地址空間 29 p = shmat(shmid, NULL, 0); 30 if (p == (void *)-1 ) 31 { 32 perror("shmget err"); 33 return errno; 34 } 35 36 printf("name:%s\n", p->name); 37 printf("age:%d \n", p->age); 38 //將共享內存段與當前進程脫離 39 shmdt(p); 40 41 printf("鍵入1 程序暫停,其他退出\n"); 42 43 int num; 44 scanf("%d", &num); 45 if (num == 1) 46 { 47 pause(); 48 } 49 return 0; 50 }
執行程序步驟以及演示結果: