No encontré una respuesta muy precisa a su pregunta, así que decidí agregar una más:
- En primer lugar, sobre la pérdida de datos, el uso de mecanismos de escritura o mmap/memcpy escribe en la memoria caché de la página y el sistema operativo los sincroniza con el almacenamiento subyacente en segundo plano en función de su configuración/algo de reemplazo de página. Por ejemplo, Linux tiene vm.dirty_writeback_centisecs que determina qué páginas se consideran "antiguas" para vaciarlas en el disco. Ahora, incluso si su proceso muere después de que la llamada de escritura haya tenido éxito, los datos no se perderán ya que los datos ya están presentes en las páginas del kernel que eventualmente se escribirán en el almacenamiento. El único caso en el que perdería datos es si el propio sistema operativo falla (pánico del kernel, apagado, etc.). La forma de asegurarse absolutamente de que sus datos hayan llegado al almacenamiento sería llamar a fsync o msync (para regiones asignadas mm), según sea el caso.
- Sobre el problema de la carga del sistema, sí, llamar a msync/fsync para cada solicitud reducirá drásticamente su rendimiento, así que hágalo solo si es necesario. Recuerde que realmente está protegiéndose contra la pérdida de datos en fallas del sistema operativo, lo que supongo que es raro y probablemente algo con lo que la mayoría podría vivir. Una optimización general realizada es emitir sincronización a intervalos regulares, digamos 1 segundo para obtener un buen equilibrio.
Encontré un comentario de Linus Torvalds que responde a esta preguntahttp://www.realworldtech.com/forum/?threadid=113923&curpostid=114068
Las páginas mapeadas son parte de la memoria caché del sistema de archivos, lo que significa que incluso si el proceso de usuario que realizó un cambio en esa página muere, el kernel aún administra la página y, dado que todos los accesos simultáneos a ese archivo pasarán por el kernel, otros los procesos se atenderán desde ese caché. En algunos kernels de Linux antiguos era diferente, esa es la razón por la que algunos documentos del kernel aún indican que se fuerce msync
.
EDITAR:Gracias, RobH corrigió el enlace.
EDITAR:
Se introduce una nueva bandera, MAP_SYNC, desde Linux 4.15, que puede garantizar la coherencia.
Las asignaciones de archivos compartidos con este indicador proporcionan la garantía de que, si bien parte de la memoria está asignada para escritura en el espacio de direcciones del proceso, será visible en el mismo archivo en el mismo desplazamiento, incluso después de que el sistema falle o se reinicie.
referencias:
http://man7.org/linux/man-pages/man2/mmap.2.html busque MAP_SYNC en la página
https://lwn.net/Articles/731706/
Decidí ser menos perezoso y responder a la pregunta de si los datos se escriben en el disco definitivamente escribiendo algún código. La respuesta es que se escribirá.
Aquí hay un programa que se mata abruptamente después de escribir algunos datos en un archivo 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);
}
Aquí hay un programa que valida el archivo resultante después de que el programa anterior está muerto:
#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");
}
Encontré algo que aumenta mi confusión:
munmap no afecta el objeto que fue asignado, es decir, la llamada a munmap no hace que el contenido de la región asignada se escriba en el archivo del disco . La actualización del archivo de disco para una región MAP_SHARED ocurre automáticamente mediante el algoritmo de memoria virtual del kernel a medida que lo almacenamos en la región mapeada en memoria.
esto es un extracto de Programación avanzada en el entorno UNIX® .
de la página de manual de Linux:
MAP_SHARED Comparte esta asignación con todos los demás procesos que asignan este objeto. Almacenar en la región es equivalente a escribir en el archivo. Es posible que el archivo no se actualice hasta que se llame a msync(2) omunmap(2).
los dos parecen contradictorios. ¿APUE es incorrecto?