linux共享内存mmap

文章来源于网络

 

(1)void *mmap(void *start, size_t len, intprot, int flag, int fd, off_t offset );

把文件或设备映射或解除映射到内存中

0)flag:必须有MAP_SHARED 标志

MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。

MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。

MAP_ANONYMOUS建立匿名共享。此时会忽略参数fd(fd可以指定为-1),不涉及文件,而且映射区域无法和其他进程共享(只能用于具有亲缘关系的进程间通信)。

    映射/dev/zero可为调用程序提供零填充的虚拟内存块。

1)start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。

2)length:代表将文件中多大的部分映射到内存。

3)offset 必须是页面大小的整数倍。页面大小由 getpagesize(2)得到。

4)被映射的文件大小应是页面大小的整数倍。如一个文件大小不是页面大小的整数倍,映射时多出来的区域将被赋为0,对这些区域的写不会被写回到文件中。

5)munmap()系统调用将删除指定地址范围内的映射区域。随后对这个范围内区域的引用将产生非法的内存引用。当这个进程终止后,这个区域也会被删除。另一方面,关闭文件描述符并不会删除映射区域。

6)fd:要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果。

7)若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1)。

(2)size_t getpagesize(void)

返回一个分页的大小,单位为字节(Byte)。该值为系统的分页大小,不一定会和硬件分页大小相同。

long psize, size;

psize = getpagesize();
size = (sizeof(aaa)/psize + 1) * psize;//sizeof计算出的大小除以每一页的大小+1,获取对应页数,再次乘以每页大小获取需要分配的地址空间

 

(2) munmap

int munmap( void * addr, size_t len )

    在进程地址空间中解除一个映射关系,当映射关系解除后,对原来映射地址的访问将导致段错误发生。

void * addr :调用mmap()时返回的地址

size_t len :映射区的大小

(3)int msync ( void * addr , size_t len,int flags)

    一般说来,进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执行该操作。可以调用msync()实现磁盘上文件与共享内存区的内容一致。

void * addr :调用mmap()时返回的地址

size_t len :映射区的大小

int flags :MS_ASYN: 异步写,MS_SYN : 同步写,MS_INVALIDAT : 无效的cache 数据。

 

 

在父子间进程通信时:

mmap((void*)a, 15, PROT_READ | PROT_WRITE,MAP_SHARED| MAP_ANONYMOUS , fd, 0);需要设置为匿名映射,映射区不与任何文件关联

代码1 :

#include<stdio.h>

#include<stdlib.h>

#include<time.h>

#include<unistd.h>

#include<fcntl.h>

#include<sys/types.h>

#include<sys/mman.h>

int main()

{

   int fd,aaa,i;

   char a[15]="kkkkkKKKKKKK";

   char  *pp;

    pid_tpid;

   fd = open("./aaa", O_RDWR);

   //開啟一個名為aaa的檔案在/aaa 內容可自己先打

   pp = (char*)mmap((void*)a, 15, PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);

   //映對檔案到記憶體,擁有可讀寫的權限

   pid = fork();

   if(pid == -1)

    {

       printf("Can't fork.\n");

        exit(1);

    }

   if(pid == 0)

    {

       int seed;

       seed = time(NULL);

       srand(seed);

       for(i=0; i < 50; i++)

           pp[i] = 'b';

       return 0;

    }

   else

    {

       wait();

       printf("P%s\n",  pp);

    }

    return 0;

}

 

代码2:

mmap_w

 

#include<stdio.h>

#include <string.h>

#include <stdlib.h>

#include<math.h>

#include<fcntl.h>

#include<sys/types.h>

#include<unistd.h>

#include<sys/mman.h>

 

typedef struct

{

   char str[512];

   long lval;

   double dval;

}SSS;

 

#define NUMBER (1000)

 

int main()

{

   int  fd;

   char c;

   long psize, size;

   SSS  *ptr;

   long i,lval;

   double dval;

   char buf[512];

 

   /* マップ用ファイルオープン*/

   if((fd = open("./MapFile",O_RDWR|O_CREAT, 0666)) == -1)

    {

       perror("open");

        exit(-1);

    }

 

   /* ページサイズで境界合わせを行なったサイズを計算 */

   // #ifdef BSD

   // psize=getpagesize();

   // #else

   // psize=sysconf(_SC_PAGE_SIZE);

   // #endif

   psize = getpagesize();

   size = (NUMBER * sizeof(SSS)/psize + 1) * psize;

 

   /* ファイルの必要サイズ分先にシークし、0を書き込み */

   /* ファイルのサイズをマップしたいサイズにする為 */

   if(lseek(fd, size, SEEK_SET) < 0)

    {

       perror("lseek");

       exit(-1);

    }

   if(read(fd, &c, sizeof(char))==-1)

    {

       c='\0';

    }

   if(write(fd, &c, sizeof(char))==-1)

    {

       perror("write");

       exit(-1);

    }

 

   /* マップ */

   ptr=(SSS *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

   if((int)ptr==-1)

    {

       perror("mmap");

       exit(-1);

    }

 

   /* テスト */

   while(1)

    {

       /* 標準入力からデータ読み込み*/

       gets(buf);

       if(feof(stdin))

       {

           break;

       }

       lval = atoi(buf);

       dval = atof(buf);

       /* 全データの値をセット */

       for(i=0;i < NUMBER; i++)

       {

           strcpy(ptr[i].str, buf);

           ptr[i].lval=lval;

           ptr[i].dval=dval;

       }

       /* 実際にファイルに書き込みたい場合はmsync()する */

       /* msync(ptr,size,MS_ASYNC); */

    }

 

       /* 実際にファイルに書き込み、同期を取る */

       msync(ptr,size,0);

 

       /* アンマップ */

    if(munmap(ptr,size)==-1)

    {

       perror("munmap");

    }

   /* ファイルクローズ */

   close(fd);

   return 1;

}

 

代码3:

 

mmap_r

 

#include <stdio.h>

#include <math.h>

#include <fcntl.h>

#include <math.h>

#include <sys/types.h>

#include <unistd.h>

#include <sys/mman.h>

#include <string.h>

#include <stdlib.h>

 

typedef struct

{

   char str[512];

   long lval;

   double dval;

}SSS;

 

#define NUMBER (1000)

 

int main()

{

   int  fd;

   long psize,size;

   SSS  *ptr;

   long i;

 

    /* マップ用ファイルオープン*/

    if((fd = open("./MapFile",O_RDWR))== -1)

    {

       perror("open");

       exit(-1);

    }

 

    // /* ページサイズで境界合わせを行なったサイズを計算 */

   // #ifdef BSD

    // psize=getpagesize();

   // #else

    // psize=sysconf(_SC_PAGE_SIZE);

   // #endif

   psize = getpagesize();

   size=(NUMBER*sizeof(SSS)/psize+1)*psize;

   

    /* マップ */

    ptr=(SSS*)mmap(0, size, PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

 

    /* テスト */

   while(1)

    {

        /* 全データの表示 */

       for(i=0;i < NUMBER;i++)

       {

           if(i%100==0)

           {

               printf("{%5d:%d,%g,%s}\n",i,ptr[i].lval,ptr[i].dval,ptr[i].str);

           }

       }

       printf("\n");

        /* 1秒待ち */

       sleep(1);

    }

   return 0;

}

 

 

5、其他

1)进程调用mmap()时,只是在进程空间内新增了一块相应大小的缓冲区,并设置了相应的访问标识,但并没有建立进程空间到物理页面的映射。因此,第一次访问该空间时,会引发一个缺页异常。

2)一个共享内存区域可以看作是特殊文件系统shm中的一个文件,shm的安装点在交换区上。

3)mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。

4)最终被映射文件的内容的长度不会超过文件本身的初始大小,即映射不能改变文件的大小。文件被映射部分而不是整个文件决定了进程能够访问的空间大小,另外,如果指定文件的偏移部分,一定要注意为页面大小的整数倍。

 





 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值