Shared memory
Mémoire partagée¤
Nous le verrons plus loin au chapitre sur la MMU, mais la mémoire d'un processus mémoire (programme) ne peut pas être accédée par un autre programme. Le système d'exploitation l'en empêche.
Lorsque l'on souhaite communiquer entre plusieurs programmes, il est possible d'utiliser différentes méthodes :
- les flux (fichiers, stdin, stdout...)
- la mémoire partagée
- les sockets
Vous avez déjà vu les flux au chapitre précédent, et les sockets ne font pas partie de ce cours d'introduction.
Notons que la mémoire partagée est un mécanisme propre à chaque système d'exploitation. Sous POSIX elle est normalisée et donc un programme compatible POSIX et utilisant la mémoire partagée pourra fonctionner sous Linux, WSL ou macOS, mais pas sous Windows.
C'est principalement l'appel système mmap
qui est utilisé. Il permet de mapper ou démapper des fichiers ou des périphériques dans la mémoire.
void *mmap(
void *addr,
size_t length, // Size in bytes
int prot, // Access protection (read/write/execute)
int flags, // Attributs (shared/private/anonymous...)
int fd,
int offset
);
Voici un exemple permettant de réserver un espace partagé en écriture et en lecture entre deux processus :
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
void* create_shared_memory(size_t size) {
// Accessible en lecture et écriture
int protection = PROT_READ | PROT_WRITE;
// D'autres processus peuvent accéder à cet espace
// lequel est anonyme
// so only this process and its children will be able to use it:
int visibility = MAP_SHARED | MAP_ANONYMOUS;
// The remaining parameters to `mmap()` are not important for this use case,
// but the manpage for `mmap` explains their purpose.
return mmap(NULL, size, protection, visibility, -1, 0);
}
File memory mapping¤
Traditionnellement lorsque l'on souhaite travailler sur un fichier, il convient de l'ouvrir avec fopen
et de lire son contenu. Lorsque cela est nécessaire, ce fichier est copié en mémoire :
FILE *fp = fopen("foo", "r");
fseek(fp, 0, SEEK_END);
int filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *file = malloc(filesize);
fread(file, filesize, sizeof(char), fp);
fclose(fp);
Cette copie n'est pas nécessairement nécessaire. Une approche POSIX, qui n'est donc pas couverte par le standard C99 consiste à lier le fichier dans un espace mémoire partagé.
Ceci nécessite l'utilisation de fonctions bas niveau.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
int main() {
int fd = open("foo.txt", O_RDWR, 0600);
char *addr = mmap(NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("Espace mappé à %p\n", addr);
printf("Premiers caractères du fichiers : %.*s...\n", 20, addr);
}
Les avantages de cette méthode sont :
- pas nécessaire de copier l'intégralité du fichier en mémoire ;
- possibilité de partager le même fichier ouvert entre plusieurs processus ;
- possibilité laissée au système d'exploitation d'utiliser la RAM ou non si les ressources mémoires deviennent tendues.