在linux 2.6内核上使用 direct io 不难,只需按照如下几点来做即可:
1,在open文件时加上 O_DIRECT 旗标,这样以通告内核我们想对该文件进行直接io操作。
2,在源文件的最顶端加上 _GNU_SOURCE 宏定义,或在编译时加在命令行上也可以,否则将提示:
direct_io_write_file.c: In function 'main': direct_io_write_file.c:25: error: 'O_DIRECT' undeclared (first use in this function) direct_io_write_file.c:25: error: (Each undeclared identifier is reported only once direct_io_write_file.c:25: error: for each function it appears in.)
3,存放文件数据的缓存区起始位置以及每一次读写数据长度必须是磁盘逻辑块大小的整数倍,一般也就是512字节(也有可能是一内存页大 小,4096),否则将导致read/write失败,perror将提示:read failed: Invalid argument或write failed: Invalid argument。
1和2很容易做到,而第3点,要满足缓存区起始位置与512对齐,这可以在进行缓存区空间申请时使用posix_memalign这样的函数指定512对齐:
ret = posix_memalign((
void
**)&buf, 512, BUF_SIZE);
|
或者进行手动调节对齐:
real_buf = malloc(BUF_SIZE + 512); aligned_buf = ((((unsigned int)real_buf + 512 - 1) / 512) * 512);
由于要满足每一次读写数据长度必须是磁盘逻辑块大小的整数倍,所以最后一次文件操作可能无法满足,此时只能重新以cached io模式打开文件后,fseek到对应位置进行剩余数据的读写。
为什么要使用direct io?因为direct io不过文件系统缓冲,也就是说对文件进行direct io操作不会减少系统的free内存数量,这对于自己本身带有缓存的应用程序(比如数据库)比较有用。
示例:
#include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <iostream> #include <string> #include <errno.h> #define BUF_SIZE 1024 bool writeFileInODirectMode(long i, unsigned char *buf) { int fd; int ret; std::string fileName("./direct_io."); char iStr[256]; sprintf(iStr, "%ld", i); fileName.append(iStr); fileName.append(".data"); fd = open(fileName.c_str(), O_DIRECT | O_CREAT | O_RDWR, S_IRWXU); if (fd < 0){ perror("open ./direct_io.data failed"); free(buf); return false; } ret = write(fd, buf, BUF_SIZE); if (ret < 0) { perror("write ./direct_io.data failed"); return false; } close(fd); return true; } bool writeFileInOSyncMode(long i, unsigned char *buf) { int fd; int ret; std::string fileName("./sync_io."); char iStr[256]; sprintf(iStr, "%ld", i); fileName.append(iStr); fileName.append(".data"); fd = open(fileName.c_str(), O_SYNC | O_CREAT | O_RDWR, S_IRWXU); if (fd < 0){ perror("open ./sync_io.data failed"); free(buf); return false; } ret = write(fd, buf, BUF_SIZE); if (ret < 0) { perror("write ./sync_io.data failed"); return false; } close(fd); return true; } bool writeFileAndWait(long i, unsigned char *buf) { int fd; int ret; std::string fileName("./wait_io."); char iStr[256]; sprintf(iStr, "%ld", i); fileName.append(iStr); fileName.append(".data"); fd = open(fileName.c_str(), O_CREAT | O_RDWR, S_IRWXU); if (fd < 0){ perror("open ./wait_io.data failed"); free(buf); return false; } ret = write(fd, buf, BUF_SIZE); if (ret < 0) { perror("write ./wait_io.data failed"); return false; } if(fdatasync(fd) != 0) { perror("sync error\n"); return false; } close(fd); return true; } int main(int argc, char * argv[]) { unsigned char *buf; int ret = posix_memalign((void **)&buf, 512, BUF_SIZE); if (ret) { perror("posix_memalign failed"); exit(1); } memset(buf, 'c', BUF_SIZE); if(!writeFileInODirectMode(1, buf)) { exit(1); }
//其他两种直写磁盘的方法 if(!writeFileInOSyncMode(2, buf)) { exit(1); } if(!writeFileAndWait(3, buf)) { exit(1); } free(buf); }