存储映射(二)——mmap函数

本文详细解析了内存映射的概念,重点讲解了进程空间中映射的位置,并通过mmap函数实例展示了如何将文件映射到进程空间,包括参数解释和munmap取消映射。特别提到映射0大小文件会导致SIGBUS错误,需确保文件非空。
摘要由CSDN通过智能技术生成

内存映射

映射时,具体映射到了进程空间的什么位置呢?

映射到了“进程应用空间”堆和栈中间那片虚拟地址的位置。

  1. 进程内核空间:用于映射“OS”所在的物理内存空间。
  2. 进程应用空间:用于映射“应用程序”所在的物理内存空间。z

mmap函数

  1. 函数原型
    • #include <sys/mman.h>
    • void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  2. 功能
    • 将文件所在磁盘空间映射到进程空间。
  3. 返回值
    • 调用成功,返回映射的起始虚拟地址,失败则返回(void *)-1,errno被设置。
  4. 参数
    • addr:人为指定映射的起始虚拟地址
      • 如果设置为NULL,表示由内核决定映射的起始虚拟地址,这也是最常见的设置方式,这与我们调用shmat映射虚拟内存指定NULL是一样的。
      • 如果不设置为NULL,而是自己指定的,指定的起始虚拟地址必须是虚拟页(4K)的整数倍,这与自己指定的shmat的映射起始虚拟地址也是一样的。
    • length:映射长度,也就是你想对文件映射多长
    • prot:指定对映射区的操作权限,可指定如下命令宏:
      • PROT_EXEC:映射区的内容可执行。
        如果你映射的是普通文件是一个可执行文件的话,将映射权限指定为PROT_EXEC后,是能够通过映射后的虚拟地址去执行文件中的“命令”。
      • PROT_READ:映射区的内容可读。
      • PROT_WRITE:映射区的内容可写。
      • 以上三种选项可相互 | 操作。
      • 比如:PROT_EXEC | PROT_READ
      • PROT_NONE:映射区不允许访问(不允许执行、读、写),一般不会指定这个,如果指定不可访问的话,映射没有意义了。
    • flags:向映射区写入了数据,是否将数据立即更新到文件中。
      • MAP_SHARED:立即更新
    • fd:需要被映射文件的描述符
    • offset:
      • 表示从文件头的offset处开始映射。
      • 一般都指定为0,表示从头文件头开始映射。

munmap:取消映射

  1. 函数原型
    • int munmap(void *addr, size_t length);
  2. 功能
    • 取消映射
  3. 返回值
    • 调用成功返回0,失败则-1,errno被设置。
  4. 参数
    • addr:映射的起始虚拟地址
    • length:需要取消映射的长度

代码演示

写一个程序,将A文件的大量数据复制到B文件中。

如果采用传统方式,使用read函数从A文件读出数据,然后向B文件write,如果数据量很大的话,复制的效率会非常低,此时我们就可以使用存储映射来实现。

失败了(BUS error)

mmap映射文件size为0的文件时,会映射失败,映射失败时内核会向进程发送一个SIGBUS信号,提示mmap失败了,这个信号的默认处理方式是终止,所以当进程收到这个信号是就被异常终止了。

如果你不想被这个信号终止,你可以自己忽略或屏蔽这个信号,一般来说我们不需要忽略和屏蔽该信号

那么解决方式就是不让目标文件size为0.

int main(int argc, char *argv[])
{
	int srcfd = -1;
	int dstfd = -1;
	void *srcaddr = NULL;
	void *dstaddr = NULL;
	struct stat src_statbuf = {0};

	/* Open the source file for reading and writing */
	srcfd = open("./file_lock.h", O_RDWR);
	if (srcfd == -1) print_err("open ./file_lock.h fail", __LINE__, errno);

	/* open the target file */
	dstfd = open("./file", O_RDWR|O_CREAT|O_TRUNC, 0664);
	if (dstfd == -1) print_err("open ./file fail", __LINE__, errno);

	/* Map source file */
	/* Get file size */
	fstat(srcfd, &src_statbuf);
	srcaddr = mmap(NULL, src_statbuf.st_size, PROT_READ, MAP_SHARED, srcfd, 0);
	if (srcaddr == (void *)-1) print_err("mmap fail", __LINE__, errno);

	/* Map destination file*/
	ftruncate(dstfd, src_statbuf.st_size);

	dstaddr = mmap(NULL, src_statbuf.st_size, PROT_WRITE, MAP_SHARED, dstfd, 0);
	if (dstaddr == (void *)-1) print_err("mmap fail", __LINE__, errno);

	/* Copy the data from the source file to the destination file */
	memcpy(dstaddr, srcaddr, src_statbuf.st_size);

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值