初窺linux共享內(nèi)存

共享內(nèi)存的linux IPC的一個(gè)方式。最簡單的解釋就是同一段物理內(nèi)存被映射到不同進(jìn)程的地址空間。任和一個(gè)被映射的進(jìn)程對該內(nèi)存的寫操作對其他被映射是可見的。
可以在命令查看當(dāng)前系統(tǒng)共享內(nèi)存的信息。


下面我們有4個(gè)文件,分別是公共文件,shm_write(創(chuàng)建共享內(nèi)存) shm_read(讀取共享內(nèi)存內(nèi)容) shm_clean(清除共享內(nèi)存內(nèi)容) common.h一個(gè)公共文件

common.h

  1 #ifndef _COMMON_H
  2 #define _COMMON_H
  3 
  4 #include <sys/types.h>
  5 #include <sys/stat.h>
  6 #include <sys/shm.h>
  7 #include <stdlib.h>
  8 
  9 #define SHM_KEY         0x00000010
 10 #define BUFFSIZE        0x00001000
 11 
 12 #define SHM_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
 13 
 14 struct shm_mm
 15 {
 16         int num;
 17         char buff[BUFFSIZE];
 18 };
 19 
 20 #endif

shm_write.c

  1 #include "common.h"
  2 #include <stdio.h>
  3 
  4 int main()
  5 {
  6         int shmid;
  7         shmid = shmget(SHM_KEY, sizeof(struct shm_mm), IPC_EXCL|IPC_CREAT|SHM_PERMS);
  8         if(shmid == -1)
  9         {
 10                 printf("shmget failed\n");
 11                 exit(1);
 12         }
 13 
 14         struct shm_mm *pshm = shmat(shmid, NULL, 0);
 15         if(pshm == (void*)-1)
 16         {
 17                 printf("shmat failed\n");
 18                 exit(2);
 19         }
 20 
 21         pshm->num = 100;
 22         for(int i = 0; i < 10 && i < BUFFSIZE; i++)
 23         {
 24                 pshm->buff[i] = 'a';
 25         }
 26 
 27 }

shm_read.c

  1 #include "common.h"
  2 #include <stdio.h>
  3 
  4 int main()
  5 {
  6         int shmid;
  7         shmid = shmget(SHM_KEY,0, 0);
  8         if(shmid == -1)
  9         {
 10                 printf("shmget failed\n");
 11                 exit(1);
 12         }
 13 
 14         struct shm_mm *pshm = shmat(shmid, NULL, 0);
 15         if(pshm == (void*)-1)
 16         {
 17                 printf("shmat failed\n");
 18                 exit(2);
 19         }
 20 
 21         printf("num=%d\n", pshm->num);
 22         for(int i = 0; i < 10 && i < BUFFSIZE; i++)
 23         {
 24                 printf("%c\t", pshm->buff[i]);
 25         }
 26          printf("\n");
 27 
 28         getchar();
 29         return 0;
 30 }

shm_clean.c

  1 #include "common.h"
  2 #include <stdio.h>
  3 
  4 int main()
  5 {
  6         int shmid = shmget(SHM_KEY, 0, 0);
  7         if(-1 == shmid)
  8         {
  9                 printf("shmget failed\n");
 10                 exit(0);
 11         }
 12         int ret = shmctl(shmid, IPC_RMID, 0);
 13         if(-1 == ret)
 14         {
 15                 printf("shmctl failed\n");
 16                 exit(1);
 17         }
 18         return 0;
 19 }

![read_out.png](http://upload-images.jianshu.io/upload_images/541012-8ff9b7b6ec4b5676.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

我們運(yùn)行shm_write進(jìn)程
查看當(dāng)前系統(tǒng)的共享內(nèi)存

2016-10-10 23-52-41屏幕截圖.png

我們可以看到最后一行, 第一列的就是我們代碼里面的SHM_KEY 權(quán)限也是我們自己設(shè)定的 SHM_PERMS, 大小是sizeof(shm_mm)。 因?yàn)閟hm_write進(jìn)程以退出,所以現(xiàn)在attach在該內(nèi)存的進(jìn)程數(shù)量為0。
我們啟動(dòng)shm_read

read_out.png

read進(jìn)程讀到了write寫進(jìn)去的數(shù)據(jù).
現(xiàn)在我們可以啟動(dòng)clean進(jìn)程清除剛才創(chuàng)建的貢獻(xiàn)內(nèi)存。也可以用命令 ipcrm -m shmid 清除掉對于的共享內(nèi)存。

通過上述實(shí)現(xiàn),我們看到,當(dāng)進(jìn)程退出后,內(nèi)核自動(dòng)會(huì)把該進(jìn)程和共享內(nèi)存的映射給清掉,就是我們通過ipcs -m 看到的attach的子段。如果我們想在進(jìn)程不退出就把這個(gè)映射這清掉。通過調(diào)用shmdt即可。

和其他共享數(shù)據(jù)一下,當(dāng)多個(gè)進(jìn)程對同一個(gè)共享內(nèi)存進(jìn)行讀寫的時(shí)候,仍然會(huì)有競爭。所以我們需要一些如信號(hào)量,進(jìn)程鎖等高級(jí)的進(jìn)程同步控制原語來進(jìn)行同步操作。
當(dāng)然,共享內(nèi)存還受到一些參數(shù)的影響.
/proc/sys/kernel/shmall:限制系統(tǒng)用在共享內(nèi)存上的內(nèi)存總頁數(shù)。注意是頁數(shù),單位為4k。
/proc/sys/kernel/shmmax:限制一個(gè)共享內(nèi)存段的最大長度,字節(jié)為單位。
/proc/sys/kernel/shmmni:限制整個(gè)系統(tǒng)可創(chuàng)建的最大的共享內(nèi)存段個(gè)數(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容