APUE学习笔记(22)-存储映射IO

By:             潘云登

Date:          2009-8-26

Email:         intrepyd@gmail.com

Homepage: http://blog.csdn.net/intrepyd

Copyright: 该文章版权由潘云登所有。可在非商业目的下任意传播和复制。

对于商业目的下对本文的任何行为需经作者同意。


写在前面

1.          本文内容对应《UNIX环境高级编程》(2)》第14章。

2.          总结了存储映射IO的基本概念和使用方法

3.          希望本文对您有所帮助,也欢迎您给我提意见和建议。


存储映射

I/O

存储映射I/OMemory-mapped I/O)使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当在缓冲区中存取数据,就相当于读写文件中的相应字节。这样就可以在不使用readwrite的情况下执行I/O

         首先,需要告诉内核将一个给定的文件映射到一个存储区域中。这由mmap函数完成。

#include <sys/mman.h>

void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off );

Returns: starting address of mapped region if OK, MAP_FAILED on error

l          addr参数指定映射存储区的起始地址。通常将其设置为0,表示由系统选择映射区的起始地址。mmap的返回地址是该映射区的起始地址。

l          filedes指定要被映射文件的描述符。在映射该文件到一个地址空间之前,先要打开该文件。

l          len是映射的字节数。

l          off是要映射字节在文件中的起始偏移量。

l          prot参数说明对映射区域的保护要求,可以是PROT_READPROT_WRITEPROT_EXECPROT_NONE。对指定映射存储区的保护要求不能超过文件open模式访问权限。

l          flag参数影响映射存储区的多种属性,取值可以是:1MAP_FIXED,表示返回值必须等于addr,这不利于可移植性;2MAP_SHARED,指示存储操作修改映射文件;3MAP_PRIVATE,说明对映射区的存储操作导致创建该映射文件的一个私有副本。

此外,需要记住以下几点:

l          offaddr的值(如果指定了MAP_FIXED)通常应当是系统虚存页长度的倍数。虚存页长度可用带参数_SC_PAGESIZE_SC_PAGE_SIZEsysconf函数得到。

l          不能用mapp将数据添加到文件中。为了做到这一点,必须首先加长该文件。

l          与映射区相关的有SIGSEGVSIGBUS两个信号。信号SIGSEGV通常用于指示进程试图访问对它不可用的存储区。如果访问映射区的某个部分,而在访问时这一部分实际上已不存在,则产生SIGBUS信号。

l          由于子进程复制父进程的地址空间,而存储映射区是该地址空间的一部分,因此,在调用fork之后,子进程继承存储映射区。由于同样的理由,调用exec后的新程序则不继承此存储映射区。


其它接口

 

调用mprotect可以更改一个现存映射存储区的权限。prot的许可值与mmapprot参数一样,地址参数addr的值必须是系统页长的整数倍。

#include <sys/mman.h>

int mprotect(void *addr, size_t len, int prot);

Returns: 0 if OK, -1 on error

如果在共享存储映射区中的页已经修改,那么可以调用msync将该页冲洗到被映射的文件中,其作用类似于fsync。如果映射是私有的,那么不修改被映射的文件。addr同样必须与页边界对齐。flags参数一定要指定MS_ASYNCMS_SYNC中的一个。如果希望在函数返回之前等待写操作完成,则可指定MS_SYNC标志。MS_INVALIDATE是一个可选标志,使用它可以通知操作系统丢弃与底层存储器没有同步的任何页。

#include <sys/mman.h>

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

Returns: 0 if OK, -1 on error

进程终止时,或调用了munmap后,存储映射区就被自动解除映射。关闭文件描述符filedes并不解除映射区。调用munmap不会使映射区的内容写到磁盘文件上。对于MAP_SHARED区磁盘文件的更新,在写到存储映射区时按内核虚存算法自动进行。在解除了映射后,对于MAP_PRIVATE存储区的修改被丢弃。

#include <sys/mman.h>

int munmap(caddr_t addr, size_t len);

Returns: 0 if OK, -1 on error

     范例程序如下:使用存储映射I/O复制一个文件。

#include "apue.h"

#include <fcntl.h>

#include <sys/mman.h>

 

int main(int argc, char *argv[])

{

    int         fdin, fdout;

    void        *src, *dst;

    struct stat statbuf;

 

    if (argc != 3)

        err_quit("usage: %s <fromfile> <tofile>", argv[0]);

 

    if ((fdin = open(argv[1], O_RDONLY)) < 0)

        err_sys("can't open %s for reading", argv[1]);

 

    if ((fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE)) < 0)

        err_sys("can't creat %s for writing", argv[2]);

 

    if (fstat(fdin, &statbuf) < 0)   /* need size of input file */

        err_sys("fstat error");

 

    /* 不能用mmap加长文件,必须首先设置文件大小 */

    if (lseek(fdout, statbuf.st_size - 1, SEEK_SET) == -1)

        err_sys("lseek error");

    if (write(fdout, "", 1) != 1)

        err_sys("write error");

 

    if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED,

      fdin, 0)) == MAP_FAILED)

        err_sys("mmap error for input");

 

    if ((dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE,

      MAP_SHARED, fdout, 0)) == MAP_FAILED)

        err_sys("mmap error for output");

 

    memcpy(dst, src, statbuf.st_size); /* does the file copy */

    exit(0);

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值