mmap函数

41 篇文章 0 订阅

mmap函数

1.创建映射区
void *mmap(void *adrr,size_t length,int prot,int flags,int fp,off_t offset);

addr:建立映射区的首地址,直接传NULL
length:映射区的大小
prot:映射区权限PROT_READ,PROT_WRITE,PROT_READ|PROT_WRITE
flags:标志位参数,MAP_SHARED将映射区所做的操作反映到物流设备(磁盘)上(父子进程可以共享映射区)
MAP_PRIVATE不反映(父子进程不共享映射区,各自独占)。
offset:映射文件的偏移(4k的整数倍)为0时表示起始位置。

成功:返回映射区的首地址,失败:返回MAP_FAILED
  • 新建立的文件不能创建映射区,也就是说,不能创建大小为0的映射区
  • 可以在堆区开辟大小为0的空间(void *malloc(unsigned int size));
  • 映射区的权限要 <= 打开文件的权限
  • 映射区创建的过程中隐含一次对文件的读操作
  • 父子进程共享mmap建立的映射区,和打开的文件
  • 当mmap中的flags参数设置成MAP_PRIVATE时,父子进程各自独占映射区,不共享。
2.关闭映射区
int munmap(void *addr,size_t length);

```c
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<string.h>

int main()
{
        int fp = open("test",O_RDWR | O_CREAT,0644);
        if(fp == -1)
        {
                perror("open error:");
                exit(1);
        }
        int file_len = truncate("test",1024);
        if(file_len == -1)
        {
                perror("truncate error");
                exit(1);
         }
        char *mp = NULL;
        mp = mmap(NULL,1024,PROT_READ | PROT_WRITE,MAP_SHARED,fp,0);
        if(mp == MAP_FAILED)
        {
                perror("mmap error:");
                exit(1);
        }
        else
        {
                strcpy(mp,"6666666666666666666\n");
                int nump = munmap(mp,1024);
                if(nump == -1)
                {
                        perror("munmap error:");
                        exit(1);
                }
                close(fp);
        }
        return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h>

int variety = 666;

int main()
{
        int fp = open("test",O_RDWR | O_CREAT | O_TRUNC,0644);
        if(fp == -1)
        {
                perror("open error:");
                exit(1);
        }
        ftruncate(fp,512);
        int len = lseek(fp,0,SEEK_END);
        printf("the length of test is:%d\n",len);
        int *mp;
        mp = mmap(NULL,len,PROT_READ | PROT_WRITE,MAP_SHARED,fp,0);
        if(mp == MAP_FAILED)
        {
                perror("mmap error:");
                exit(1);
        }
        close(fp);
		int ul = unlink("test");
        if(ul == 0)
        {
                printf("file is deleted successful\n");
        }
        pid_t pid = fork();
        if(pid == 0)
        {
                printf("I am child\n");
                *mp = 999;
                variety = 888;
                printf("*mp = %d,variety = %d\n",*mp,variety);
        }
        else
        {
        		sleep(1);
                printf("I am father\n");
                printf("*mp = %d,variety = %d\n",*mp,variety);
                wait(NULL);
        }
        int numap = munmap(mp,len);
        if(numap == -1)
                {
                        perror("numap error:");
                        exit(1);
                }
        return 0;

}

匿名映射:

 - 无需依赖一个文件即可建立映射区
 - 在参数flags中加入:MAP_ANONYMOUS(ANON)

```cpp
int*p=mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,O);
  • 需注意的是,MAP_ANONYMOUS和MAP_ANON这两个宏是Linux操作系统特有的宏。在类Unix系统中如无宏定义,可使用如下两步来完成匿名映射区的建立。
int fd=open("/dev/zero",O_RDWR);
p=mmap(NULL,size,PROT_READ|PROT_WRITE,MMAP_SHARED,fd,0);
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h>

int variety = 666;

int main()
{
        int *mp;
        mp = mmap(NULL,128,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANON,-1,0);
        if(mp == MAP_FAILED)
        {
                perror("mmap error:");
                exit(1);
        }
        pid_t pid = fork();
        if(pid == 0)
        {
                printf("I am child\n");
                *mp = 999;
                variety = 888;
                printf("*mp = %d,variety = %d\n",*mp,variety);
        }
        else
        {
                sleep(1);
                printf("I am father\n");
                printf("*mp = %d,variety = %d\n",*mp,variety);
                wait(NULL);
        }
        int numap = munmap(mp,128);
        if(numap == -1)
                {
                        perror("numap error:");
                        exit(1);
                }
        return 0;
 }

总结:使用mmap时务必注意以下事项:

1.创建映射区的过程中,隐含着一次对映射文件的读操作。
2.当MAP_SHARED时,要求:映射区的权限应<=文件打开的权限(出于对映射区的保护)。而MAP_PRIVATE则无所谓,因为mmapf的权限是对内存的限制。
3.映射区的释放与文件关闭无关。只要映射建立成功,文件可以立即关闭。
4.特别注意,当映射文件大小为0时,不能创建映射区。所以:用于映射的文件必须要有实际大小!mmap.使用时常常会出现总线错误,通常是由于共享文件存储空间大小引起的。
5.munmap.传入的地址一定是mmap的返回地址。坚决杜绝指针++/- -操作。
6.offset文件偏移量必须为4K的整数倍
7.mmap创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续操作。
8.因为创建mmap函数比较容易出错,所以创建完成后一定要通过判断返回值来确定是否创建成功

将结构体写入文件中
#include<sys/mman.h>
#include<sys/wait.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>

struct stu{
        int num;
        char name[16];
        int class;
};

int main(int argc,char *argv[])
{
        struct stu student = {1,"zjl",11};
        if (argc<2)
        {
                printf("argument is less\n");
                exit(1);
        }
        int fp = open(argv[1],O_RDWR | O_CREAT | O_TRUNC,0644);
        int len = sizeof(student);
        printf("student len is:%d\n",len);
        ftruncate(fp,128);
        int length = lseek(fp,0,SEEK_END);
        printf("the len of fp is:%d\n",length);

        int *mp = mmap(NULL,len,PROT_WRITE | PROT_READ,MAP_SHARED,fp,0);
        if(mp == MAP_FAILED)
        {
                perror("mmap error:");
                exit(1);
        }
        close(fp);
        while(1)
        {
                printf("enter while len is:%d\n",len);
                printf("student.name = %s\n",student.name);
                memcpy(mp,&student,64);
                student.num++;
                sleep(1);
        }
        int numap = munmap(mp,128);
        if(numap == -1)
                {
                        perror("numap error:");
                        exit(1);
                }

        return 0;
}

2个不相关进程间的通信

先写入shared_file文件中
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>

struct stu{
        int num;
        char name[16];
        int class;
};

int main(int argc,char *argv[])
{
        struct stu student = {1,"zjl",11};
        int fp = open("sharerd_file",O_RDWR | O_CREAT | O_TRUNC,0644);
        int len = sizeof(student);
        printf("student len is:%d\n",len);
        ftruncate(fp,128);

        int *mp = mmap(NULL,len,PROT_WRITE | PROT_READ,MAP_SHARED,fp,0);
        if(mp == MAP_FAILED)
        {
                perror("mmap error:");
                exit(1);
        }
        close(fp);
        printf("start to write!!!\n");
        int n = 0;

        while(1)
        {
                n += 1;
                printf("[%d]write\n",n);
                memcpy(mp,&student,64);
                student.num++;
                student.class++;
                sleep(1);
        }
        int numap = munmap(mp,128);
        if(numap == -1)
                {
                        perror("numap error:");
                        exit(1);
                }

        return 0;
}
再从文件中读出
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>

struct stu{
        int num;
        char name[16];
        int class;
};

int main(int argc,char *argv[])
{
        struct stu student;
        int fp = open("sharerd_file",O_RDONLY);

        struct stu *mp = mmap(NULL,sizeof(student),PROT_READ,MAP_SHARED,fp,0);
        if(mp == MAP_FAILED)
        {
                perror("mmap error:");
                exit(1);
        }

        close(fp);
        printf("开始接受!!!\n");
        while(1)
        {
                sleep(1);
                printf("num = %d,name = %s,class = %d\n",mp->num,mp->name,mp->class);
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值