mmap,munmap——
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void *addr, size_t length);
int mprotect(void *addr, size_t len, int prot);
int msync(void *addr, size_t length, int flags);
mmap, munmap - map or unmap files or devices into memory.
存储映射IO使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区取数据,就相当于读文件中的相应字节。与此类似,将数据存入缓冲区,则相应字节就自动地写入文件。这样就可以在不使用read和write的情况下执行IO。为了使用这种功能,应首先告诉内核将一个给定的文件映射到一个存储区域中,这是由mmap函数实现的。
addr参数用于指定映射存储区的起始地址,通常将其设置为0,这表示由系统选择该映射区的起始地址,此函数的返回地址是该映射区的起始地址。
fd指定要被映射文件的描述符,在映射该文件到一个地址空间之前,先要打开该文件。
length是映射的字节数。
offset是要映射字节在文件中的起始偏移量。
prot参数说明对映射存储区的保护要求,但不能超过文件open模式访问权限,prot可选值如下:
PROT_EXEC Pages may be executed.
PROT_READ Pages may be read.
PROT_WRITE Pages may be written.
PROT_NONE Pages may not be accessed.
flags参数影响映射存储区的多种属性,其中MAP_SHARED和MAP_PRIVATE两者必须选择其一,还有许多其它的MAP_XXX是可选的。
mprotect函数可以更改一个现有映射存储区的权限,msync函数类似于fsync,作用于存储映射区,将该页冲洗到被映射的文件中。
SIGSEGV和SIGBUS是两个与映射存储相关的两个信号。前者通常用于指示进程试图访问对它不可用的存储区,如只读的映射存储区,后者指示访问映射区不存在的部分。
调用fork后,子进程继承映射存储区,但exec后的新程序则不继承。
下面是一个用存储映射IO复制文件的例子,与read/write相比,不同操作系统下的用户和系统CPU时间可能不同,但时钟时间明显是存储映射IO要比read/write快一点。因为:用read和write时,要先将数据从内核缓冲区复制read到应用程序缓冲区,然后又将应用程序缓冲区中的数据复制write到内核缓冲区;而用mmap和munmap时,则直接将映射到应用程序地址空间的一个内核缓冲区中的数据复制到另一个同样映射到应用程序地址空间中的内核缓冲区中。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char *argv[])
{
int fdin;
int fdout;
void *src;
void *dst;
struct stat statbuf;
if (3 != argc) {
printf("usage: %s <fromfile> <tofile>\n", argv[0]);
return -1;
}
if ((fdin = open(argv[1], O_RDONLY)) < 0) {
printf("can‘t create %s for reading\n", argv[1]);
return -1;
}
if ((fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC)) < 0) {
printf("can‘t create %s for writing\n", argv[2]);
return -1;
}
if (fstat(fdin, &statbuf) < 0) {
printf("fstat error\n");
return -1;
}
if (lseek(fdout, statbuf.st_size - 1, SEEK_SET) == -1) {
printf("lseek error\n");
return -1;
}
if (write(fdout, "", 1) != 1) {
printf("write error\n");
return -1;
}
if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0)) == MAP_FAILED) {
printf("mmap error for input\n");
return -1;
}
if ((dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0)) == MAP_FAILED) {
printf("mmap error for output\n");
return -1;
}
memcpy(dst, src, statbuf.st_size);
exit(0);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。