te explico: supongamos que este es un plato compartido... |
Vamos a ver lo que contiene la librería (libmmap.c)... ¡vamos con el codigo!
#include <stdio.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include "libmmap.h" // memMapOpen() - abre un memory mapped file Message *memMapOpen( const char *memname) { // abre un memory mapped file (el file "memname" se crea en /dev/shm) int fd; if ((fd = shm_open(memname, O_CREAT | O_RDWR, 0666)) < 0) { fprintf(stderr, "shm_open error: %s\n", strerror(errno)); return NULL; } // trunca un memory mapped file if (ftruncate(fd, sizeof(Message)) < 0) { fprintf(stderr, "ftruncate error: %s\n", strerror(errno)); return NULL; } // mapea un memory mapped file Message *ptr; if ((ptr = mmap(NULL, sizeof(Message), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) < 0) { fprintf(stderr, "mmap error: %s\n", strerror(errno)); return NULL; } return ptr; } // memMapClose() - cierra un memory mapped file int memMapClose( Message *ptr, const char *memname) { // un-mapea un memory mapped file if (munmap(ptr, sizeof(Message)) < 0) { fprintf(stderr, "munmap error: %s\n", strerror(errno)); return -1; } // borra un memory mapped file if (shm_unlink(memname) < 0) { fprintf(stderr, "shm_unlink error: %s\n", strerror(errno)); return -1; } } // memMapFlush() - flush de un memory mapped file int memMapFlush( Message *ptr) { // sync en disco de un memory mapped file return msync(ptr, sizeof(Message), MS_SYNC); }Como se puede ver, no es mucha cosa pero densa. Como siempre, el código es auto-explicativo, ampliamente comentado y los comentarios hablan por sí mismos.
Las funciones de open, close y flush usan las oportunas system call Linux/POSIX para tratar el nuestro Memory Mapped File. La función de flush es sólo un wrapper para la llamada msync() y, normalmente, no es necesario utilizarla: con esta librería queremos tratar a los archivos mapeados en memoria para compartir datos entre procesos, por lo que, no sólo nos interesa poco que el archivo tenga una imagen real en el disco, sino que, por una simple cuestión de rendimiento, deberíamos evitar de descargar en el disco todos los cambios realizados en la memoria, si no seria como usar files reales. Entonces, ¿de que sirve el flush? Sirve sólo para mantener una eventual versión real y actualizada del file compartido, en el caso que queremos tratarlo, también, con la clásicas funciones open(), close(), read(), etc. Por esto en el file msgwriter.c descritos en el post anterior la llamada memMapFlush() está comentada y descrita como opcional.
¿Y el clásico parámetro size donde está? Bueno, esta es una librería especializada para un tipo específico que hemos definido (el tipo Message), entonces dentro de la librería podemos usar sizeof(Message) como y cuando queremos. El size, sin embargo, se utiliza para funciones de librerías más genéricas (que tratan tipos void*), en las cuales el campo de datos puede contener varias cosas y la función puede disponer del size de los datos sólo a través de un parámetro apósito.
Deberes para las vacaciones de la Semana Santa: hacer una versión genérica de la librería utilizando void *ptr en lugar de Mensaje *ptr en todas las funciones (¡acordarse de añadir también el size!). Os daréis cuenta que hay que hacer muy pocos cambios, una cosa muy simple. ¡Confiar en el vuestro C-Blogger favorito!
¡Hasta el próximo post!