首先

Direct IO是一种不用内核缓存的IO, 它可以做到直接将用户空间的内存直接写入磁盘或者将磁盘数据直接读到用户空间的缓冲区,这种策略就是不用内核的缓存而使用用户自己设计的缓存. 需要注意的是,使用DirectIO会完全绕过系统的预取(prefetch)以及页缓存机制,如果不是必须,那么我认为还是优先考虑普通的read或者直接mmap吧

Linux

几个方面注意一下就可以了

  • 在调用open(pathname, flags, mode)时,把O_DIRECT加上。比如int fd = open("/path/to/file", O_DIRECT, O_RDONLY);
  • 用于文件读写的buffer,必须和磁盘的块大小对齐(保守起见一般可以设为4KB)。有两种方法能拿到地址对齐的内存块:
    • 直接使用posix_memalign;
    • 直接new一段内存,然后根据返回的内存地址,往后找到第一个满足对齐要求的地址就可以。这种方法会浪费前面一段空间,不过其实posix_memalign在系统操作的时候"浪费"了;
    • 借用mmap申请MAP_ANONYMOUS匿名映射,addr参数填NULL的话mmap出来的地址是页对齐的(至少是4K对齐),所以可以直接拿来用;
  • 如果需要lseek之类的操作,注意seek的文件位置偏移量必须是磁盘块大小的整数倍;
  • 2.4内核下, 每次文件读写的长度必须是块大小的整数倍(e.g. N * 4KB). Linux 2.6.0+无此要求;

Windows下

参考这篇文章,可以知道Windows下也可以启用类似的机制,对应的打开文件flag是FILE_FLAG_NO_BUFFERING. 用法类似,与Linux不同的地方在于:

  • CreateFileA(...)调用的dwFlagsAndAttributes参数里把FILE_FLAG_NO_BUFFERING填上;
  • 用于文件读写的buffer也是需要对齐的
    • 也可以使用类似的方法_aligned_malloc申请对齐的内存,但是必须注意要使用_aligned_free释放内存,否则runtime error;