目录
mmap
参数addr
参数length
参数prot
参数flags
参数fd
参数offset
返回值
保险使用方式
munmap
参数addr
参数length
返回值
测试代码1
测试结果
使用注意事项
测试代码2
测试结果
测试代码3
测试结果
匿名映射
测试代码4
测试结果
mmap
将一个指定文件映射到存储区域中。
man 2 mmap
参数addr
指定映射区的首地址。通常传NULL,让系统自动分配。
参数length
共享内存映射区的大小,小于等于文件的实际大小。
参数prot
共享内存映射区的读写属性,映射区权限。
可传参数:
PROT_READ
PROT_WRITE
PROT_READ|PROT_WRITE
参数flags
标注共享内存的共享属性,标志位参数,常用于设定更新物理区域、设置共享、创建匿名映射区。
可传参数:
MAP_SHARED:会将映射区所做的操作反映到物理设备(磁盘)上。
MAP_PRIVATE:映射区所做的修改不会反映到物理设备。
参数fd
用于创建共享内容映射区的文件的文件描述符。
参数offset
偏移位置,必须是4k的整数倍。
0:默认值,表示映射文件全部。
返回值
成功:映射区的首地址。
失败:MAP_FAILED。
保险使用方式
fd=open("文件名",O_RDWR);
data=mmap(NULL,有效文件大小,PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
munmap
释放映射区。
参数addr
映射区首地址。
参数length
映射区大小。
返回值
成功:0
失败:-1
测试代码1
建立文件映射,读取并写入其他内容。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>int main(int argc, char *argv[])
{int fd, flag;char *data = NULL;char data1[1024];int leng;printf("程序开始运行。\n");printf("开始打开文件。\n");fd = open("temp.txt", O_RDWR);if (fd == -1){perror("打开文件错误");exit(1);}printf("打开文件完成。\n");printf("开始文件映射。\n");leng = lseek(fd, 0, SEEK_END);data = mmap(NULL, leng, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //全部映射if (data == MAP_FAILED){perror("文件映射错误");exit(1);}printf("文件映射完成。\n");printf("地址是%d。\n", *data);printf("内容是:%s", data);printf("开始写入文件。\n");printf("写入的内容是:hello,world.\n");strcpy(data, "hello,world.\n");printf("写入文件完成。\n");close(fd);return 0;
}
测试结果
映射多大的内存空间,只能写入多大的内存空间。映射后的返回值是文件里的内容。
使用注意事项
用于创建映射区的文件大小为0时,实际指定非0大小创建映射区,报“总线错误”。
用于创建映射区的文件大小为0时,实际指定0大小创建映射区,报“无效参数”。
用于创建映射区的文件读写属性为只读时,映射区属性为读、写,报“无效参数”。
创建映射区需要read权限,当访问权限指定为“共享/MAP_SHARED”时,mmap的读写权限应该小于等于文件的open权限。
文件描述符fd,在mmap创建映射区完成后即可关闭。后续可以使用地址访问文件。
offset必须是4096的整数倍,因为MMU映射的最小单位为4k。
对申请的映射区内存,不能越界访问。
munmap用于释放地址,必须是mmap申请返回的地址。
映射区访问权限为“私有/MAP_PRIVATE”时,对内存所做的所有修改,只在内存有效,不会反应到物理磁盘上。
映射区访问权限为“私有/MAP_PRIVATE”时,只需要open文件时,有读权限用于创建映射区即可。
测试代码2
父子进程间通过映射区进行通信。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>int main(int argc, char *argv[])
{int fd, flag;int *di_zhi;pid_t JinCheng_ID;int temp = 100;printf("程序开始运行。\n");printf("开始打开文件。\n");fd = open("temp2.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd == -1){perror("打开文件错误");exit(1);}printf("打开文件完成。\n");printf("开始文件拓展。\n");ftruncate(fd, 10);printf("文件拓展完成。\n");printf("开始文件映射。\n");di_zhi = (int *)mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //全部映射if (di_zhi == MAP_FAILED){perror("文件映射错误");exit(1);}close(fd);printf("文件映射完成。\n");printf("开始创建进程。\n");JinCheng_ID = fork();if (JinCheng_ID == 0) //子进程{*di_zhi = 1000;temp = 200;printf("这是子进程,*di_zhi=%d,temp=%d。\n", *di_zhi, temp);}else if (JinCheng_ID > 0) //父进程{sleep(1);printf("这是父进程,*di_zhi=%d,temp=%d。\n", *di_zhi, temp);wait(NULL);}printf("开始释放映射区。\n");flag = munmap(di_zhi, 10);printf("释放映射区完成。\n");return 0;
}
测试结果
测试代码3
两个毫无关系的进程通过映射区进行通信。
/*
CeShi3_1.c
发送数据的进程
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>struct XueSheng
{int id;char ming_zi[256];int nian_ling;
};int main(int argc, char *argv[])
{int fd;struct XueSheng xue_sheng = {1, "张三", 20};struct XueSheng *di_zhi;printf("程序开始运行。\n");printf("开始打开文件。\n");fd = open("temp3.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd == -1){perror("打开文件错误");exit(1);}printf("打开文件完成。\n");printf("开始文件拓展。\n");ftruncate(fd, sizeof(xue_sheng));printf("文件拓展完成。\n");printf("开始文件映射。\n");di_zhi = mmap(NULL, sizeof(xue_sheng), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //全部映射if (di_zhi == MAP_FAILED){perror("文件映射错误");exit(1);}close(fd);printf("文件映射完成。\n");printf("开始向映射区发送数据。\n");while(1){memcpy(di_zhi,&xue_sheng,sizeof(xue_sheng));printf("发送的数据:id=%d,ming_zi=%s,nian_ling=%d。\n", di_zhi->id, di_zhi->ming_zi, di_zhi->nian_ling);xue_sheng.id++;sleep(1);}printf("开始释放映射区。\n");munmap(di_zhi, sizeof(xue_sheng));printf("释放映射区完成。\n");return 0;
}
/*
CeShi3_2.c
接收数据的进程
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>struct XueSheng
{int id;char ming_zi[256];int nian_ling;
};int main(int argc, char *argv[])
{int fd;struct XueSheng xue_sheng;struct XueSheng *di_zhi;printf("程序开始运行。\n");printf("开始打开文件。\n");fd = open("temp3.txt", O_RDWR);if (fd == -1){perror("打开文件错误");exit(1);}printf("打开文件完成。\n");printf("开始文件映射。\n");di_zhi = mmap(NULL, sizeof(xue_sheng), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //全部映射if (di_zhi == MAP_FAILED){perror("文件映射错误");exit(1);}close(fd);printf("文件映射完成。\n");printf("开始向映射区接收数据。\n");while (1){printf("接收的的数据:id=%d,ming_zi=%s,nian_ling=%d。\n", di_zhi->id, di_zhi->ming_zi, di_zhi->nian_ling);sleep(1);}printf("开始释放映射区。\n");munmap(di_zhi, sizeof(xue_sheng));printf("释放映射区完成。\n");return 0;
}
测试结果
匿名映射
只能用于血缘关系进程间的通信。
测试代码4
父子进程间使用匿名映射通信。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>int main(int argc, char *argv[])
{int flag;int *di_zhi;pid_t JinCheng_ID;int temp = 100;printf("程序开始运行。\n");printf("开始文件映射。\n");di_zhi = (int *)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); //全部映射if (di_zhi == MAP_FAILED){perror("文件映射错误");exit(1);}printf("文件映射完成。\n");printf("开始创建进程。\n");JinCheng_ID = fork();if (JinCheng_ID == 0) //子进程{*di_zhi = 1000;temp = 200;printf("这是子进程,*di_zhi=%d,temp=%d。\n", *di_zhi, temp);}else if (JinCheng_ID > 0) //父进程{sleep(1);printf("这是父进程,*di_zhi=%d,temp=%d。\n", *di_zhi, temp);wait(NULL);}printf("开始释放映射区。\n");flag = munmap(di_zhi, 10);printf("释放映射区完成。\n");return 0;
}