Tengo un código en el que con frecuencia copio un gran bloque de memoria, a menudo después de realizarle solo cambios muy pequeños.
Implementé un sistema que realiza un seguimiento de los cambios, pero pensé que sería bueno, si es posible, decirle al sistema operativo que haga una ‘copia en escritura’ de la memoria, y dejar que se ocupe solo de hacer una copia de esas partes. que cambio. Sin embargo, aunque Linux copia en escritura, por ejemplo, cuando se bifurca (), no puedo encontrar una manera de controlarlo y hacerlo yo mismo.
Su mejor oportunidad es probablemente mmap()
los datos originales al archivo, y luego mmap()
el mismo archivo de nuevo usando MAP_PRIVATE
.
Dependiendo de qué es exactamente lo que está copiando, un estructura de datos persistente podría ser una solución para su problema.

Gunther piez
Es más fácil implementar copy-on-write en un lenguaje orientado a objetos, como c++. Por ejemplo, la mayoría de las clases de contenedor en Qt son de copia en escritura.
Pero si, por supuesto, también puedes hacer eso en C, es solo un poco más de trabajo. Cuando desea asignar sus datos a un nuevo bloque de datos, no hace una copia, sino que simplemente copia un puntero en una estructura de envoltura alrededor de sus datos. Debe realizar un seguimiento en sus bloques de datos del estado de los datos. Si ahora cambia algo en su nuevo bloque de datos, hace una copia “real” y cambia el estado. Por supuesto, ya no puede usar los operadores simples como “=” para la asignación, sino que necesita tener funciones (en C ++, solo haría una sobrecarga de operadores).
Una implementación más robusta debería usar contadores de referencia en lugar de una bandera simple, se lo dejo a usted.
Un ejemplo rápido y sucio: si tienes un
struct big {
//lots of data
int data[BIG_NUMBER];
}
tiene que implementar funciones de asignación y getters/setters usted mismo.
// assume you want to implent cow for a struct big of some kind
// now instead of
struct big a, b;
a = b;
a.data[12345] = 6789;
// you need to use
struct cow_big a,b;
assign(&a, b); //only pointers get copied
set_some_data(a, 12345, 6789); // now the stuff gets really copied
//the basic implementation could look like
struct cow_big {
struct big *data;
int needs_copy;
}
// shallow copy, only sets a pointer.
void assign(struct cow_big* dst, struct cow_big src) {
dst->data = src.data;
dst->needs_copy = true;
}
// change some data in struct big. if it hasn't made a deep copy yet, do it here.
void set_some_data(struct cow_big* dst, int index, int data } {
if (dst->needs_copy) {
struct big* src = dst->data;
dst->data = malloc(sizeof(big));
*(dst->data) = src->data; // now here is the deep copy
dst->needs_copy = false;
}
dst->data[index] = data;
}
También necesita escribir constructores y destructores. Realmente recomiendo c++ para esto.

DevSolar
El mecanismo de copia en escritura empleado, por ejemplo, por fork() es una característica de la MMU (Unidad de administración de memoria), que maneja la paginación de memoria para el kernel. El acceso a la MMU es una operación privilegiada, es decir, no se puede realizar mediante una aplicación de espacio de usuario. Tampoco tengo conocimiento de ninguna API de copia en escritura exportada al espacio del usuario.
(Por otra parte, no soy exactamente un gurú en la API de Linux, por lo que otros podrían señalar llamadas de API relevantes que me he perdido).
Editar: Y he aquí, MSalters está a la altura de las circunstancias. 😉
Debería poder abrir su propia memoria a través de /proc/$PID/mem y luego mmap() la parte interesante con MAP_PRIVATE a algún otro lugar.

abeja desvanecida
Aquí hay un ejemplo de trabajo:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SIZE 4096
int main(void) {
int fd = shm_open("/tmpmem", O_RDWR | O_CREAT, 0666);
int r = ftruncate(fd, SIZE);
printf("fd: %i, r: %i\n", fd, r);
char *buf = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
printf("debug 0\n");
buf[SIZE - 2] = 41;
buf[SIZE - 1] = 42;
printf("debug 1\n");
// don't know why this is needed, or working
//r = mmap(buf, SIZE, PROT_READ | PROT_WRITE,
// MAP_FIXED, fd, 0);
//printf("r: %i\n", r);
char *buf2 = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0);
printf("buf2: %i\n", buf2);
buf2[SIZE - 1] = 43;
buf[SIZE - 2] = 40;
printf("buf[-2]: %i, buf[-1]: %i, buf2[-2]: %i, buf2[-1]: %i\n",
buf[SIZE - 2],
buf[SIZE - 1],
buf2[SIZE - 2],
buf2[SIZE - 1]);
unlink(fd);
return EXIT_SUCCESS;
}
No estoy seguro de si necesito habilitar la sección comentada, por seguridad.
¿Qué tipo de datos estás copiando? Copy-on-write podría no ser la única solución.
–Jorgen Fogh
14 de octubre de 2009 a las 9:54