BD *_*ill 26 c linux linux-kernel
我想使用mmap在Linux下运行的C程序中实现程序状态的某些部分的持久性,方法是使用设置了MAP_SHARED标志的mmap()将固定大小的结构与众所周知的文件名相关联.出于性能原因,我宁愿根本不调用msync(),也不会有其他程序访问此文件.当我的程序终止并重新启动时,它将再次映射同一个文件并对其进行一些处理以恢复它在终止之前所处的状态.我的问题是:如果我从不在文件描述符上调用msync(),内核是否会保证对内存的所有更新都会写入磁盘并随后可以恢复,即使我的进程是以SIGKILL终止的?此外,即使我的程序从不调用msync(),内核是否会定期将页面写入磁盘?
编辑:我已经解决了数据是否写入的问题,但我仍然不确定这是否会导致一些意外的系统加载,而不是试图用open()/ write()/ fsync()来处理这个问题承担KILL/SEGV/ABRT /等过程中某些数据可能丢失的风险.添加了一个'linux-kernel'标签,希望有些知识渊博的人可以加入.
Pat*_*ter 20
我发现从Linus Torvalds的是回答这个问题的注释 http://www.realworldtech.com/forum/?threadid=113923&curpostid=114068
映射页面是文件系统缓存的一部分,这意味着即使对该页面进行了更改的用户进程终止,该页面仍然由内核管理,并且所有对该文件的并发访问都将通过内核,其他进程将从该缓存中提供.在一些旧的Linux内核中它是不同的,这就是为什么一些内核文件仍然有效的原因msync
.
编辑:谢谢RobH纠正了链接.
BD *_*ill 13
我决定不那么懒惰,并回答是否通过编写代码将数据写入磁盘的问题.答案是它将被写入.
这是一个程序,在将一些数据写入mmap'd文件后突然终止:
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef struct {
char data[100];
uint16_t count;
} state_data;
const char *test_data = "test";
int main(int argc, const char *argv[]) {
int fd = open("test.mm", O_RDWR|O_CREAT|O_TRUNC, (mode_t)0700);
if (fd < 0) {
perror("Unable to open file 'test.mm'");
exit(1);
}
size_t data_length = sizeof(state_data);
if (ftruncate(fd, data_length) < 0) {
perror("Unable to truncate file 'test.mm'");
exit(1);
}
state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, fd, 0);
if (MAP_FAILED == data) {
perror("Unable to mmap file 'test.mm'");
close(fd);
exit(1);
}
memset(data, 0, data_length);
for (data->count = 0; data->count < 5; ++data->count) {
data->data[data->count] = test_data[data->count];
}
kill(getpid(), 9);
}
Run Code Online (Sandbox Code Playgroud)
这是一个在前一个程序死后验证结果文件的程序:
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
typedef struct {
char data[100];
uint16_t count;
} state_data;
const char *test_data = "test";
int main(int argc, const char *argv[]) {
int fd = open("test.mm", O_RDONLY);
if (fd < 0) {
perror("Unable to open file 'test.mm'");
exit(1);
}
size_t data_length = sizeof(state_data);
state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
if (MAP_FAILED == data) {
perror("Unable to mmap file 'test.mm'");
close(fd);
exit(1);
}
assert(5 == data->count);
unsigned index;
for (index = 0; index < 4; ++index) {
assert(test_data[index] == data->data[index]);
}
printf("Validated\n");
}
Run Code Online (Sandbox Code Playgroud)
我发现有些东西增加了我的困惑:
munmap不会影响映射的对象,即对munmap的调用不会导致映射区域的内容写入磁盘文件.当我们存储到内存映射区域时,内核的虚拟内存算法会自动更新MAP_SHARED区域的磁盘文件.
这摘自UNIX®环境中的高级编程.
来自linux手册页:
MAP_SHARED与映射此对象的所有其他进程共享此映射.存储到该区域等同于写入文件. 在调用msync(2)或munmap(2)之前,实际上可能不会更新该文件.
这两者似乎相互矛盾.APUE错了吗?
我没有找到你问题的非常精确的答案,所以决定再添加一个: