我试图制作一个日志文件类,我想遵循的过程是:
- 打开文件(或创建文件)
- 将文件映射到内存
- 关闭文件
- 写入内存
文件的大小为 1024KB(SIZE_KB 常量)。
到目前为止,这就是我正在做的:
我创建的文件具有所有者的读写权限 (S_IRUSR | S_IWUSR) 和其余的读取权限 (S_IRGRP | S_IROTH)。
// Open the file. If the file doesnt exists it will create it
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int fd = open(path.c_str(), O_CREAT | O_RDWR, mode);
之后,我检查 fd
是否为 -1
:
if (fd < 0)
throw std::system_error(errno, std::system_category(), "couldnt open history");
#ifdef _DEBUG_
std::clog << "History with file descriptor " << fd << " opened" << std::endl;
#endif
现在,我映射文件,但首先我需要设置一个可变长度,该文件的大小必须是 sysconf(_SC_PAGE_SIZE)
的倍数:
size_t length = (int)ceil(SIZE_KB*1024.0/sysconf(_SC_PAGE_SIZE))*sysconf(_SC_PAGE_SIZE);
/* ceil( size / page_size)*page_size*/
#ifdef _DEBUG_
std::clog << "Length is " << length << " bytes" << std::endl;
#endif
映射,block_start
是一个私有(private)的char指针:
block_start = (char*)mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- 附加问题:M_SHARED 选项使这部分内存可以被其他进程访问(?)。为什么还用它来让SO把虚拟内存中的修改保存到实际文件中?。
检查错误:
#ifdef _DEBUG_
std::clog << Returned: " << (int*)block_start << std::endl;
#endif
if (block_start == MAP_FAILED)
throw std::system_error(errno, std::system_category(), "couldnt map memory");
#ifdef _DEBUG_
std::clog << "History memory mapped" << std::endl;
#endif
然后关闭文件:
int result = close(fd);
if (result < 0)
throw std::system_error(errno, std::system_category(), "error closing history");
#ifdef _DEBUG_
std::clog << "History with file descriptor " << fd << " closed" << std::endl;
#endif
现在,我应该能够将信息添加到映射内存中,所以我尝试这样做:
std::cout << "Attemping to write on first" << std::endl;
*block_start = 'A';
std::cout << "End" << std::endl;
(在构造函数内部)
这是我的输出:
History with file descriptor 3 opened
Length is 1048576 bytes
Returned: 0x7f7e9160a000
History memory mapped
History with file descriptor 3 closed
Attemping to write on first
Bus error (core dumped)
我认为这可能与文件大小有关,因为创建的文件大小为 0,但我告诉 mmap 映射大小为 SIZE_KB*1024
字节,那么为什么这不起作用?
-rw-r--r-- 1 dark dark 0 Dec 13 16:15 /home/dark/talk.log
最佳答案
因为 mmap 不会映射超出文件大小。如果您正在映射一个空文件,则您的有效 mmap 大小为 0。
在映射之前,您需要通过 truncate() 或 ftruncate() 设置文件的大小,并且文件的大小和映射的大小必须一致。
关于c++ - 不太清楚为什么 mmap 没有按照我认为应该的方式进行。 C++ Linux,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34254043/