HOWTO · C
Verwenden Sie die mmap-Funktion, um in C in den Speicher zu schreiben
Dieser Artikel informiert über die Funktion mmap() und zeigt, wie wir die Funktion verwenden können, um in den Speicher in C zu schreiben.
Auf dieser Seite
mmap() erstellt eine Speicherabbildung in einem Prozess. Eine beschreibbare anonyme Abbildung lässt sich als Speicher für C-Daten verwenden; eine gemeinsam genutzte anonyme Abbildung kann Änderungen zwischen verwandten Prozessen übertragen. Diese Anleitung erläutert die sechs Argumente, zeigt, wie sich Fehler beim Erstellen einer Abbildung erkennen lassen, und erklärt, wie sie mit munmap() freigegeben wird.
Was mmap() bewirkt und zurückgibt
Eine Speicherabbildung verknüpft einen Bereich des virtuellen Adressraums eines Prozesses mit einer Datei, einem Gerät oder anonymem Speicher. Anonymer Speicher ist nicht durch eine Datei hinterlegt; Änderungen daran werden daher nicht in einer Datei gespeichert. Binden Sie <sys/mman.h> ein, um mmap() und die zugehörigen Konstanten zu verwenden.
Die Funktion nimmt sechs Argumente entgegen und gibt bei Erfolg die Adresse der neuen Abbildung zurück. Bei einem Fehler gibt sie MAP_FAILED zurück. Vergleichen Sie den Rückgabewert daher mit diesem speziellen Wert, statt auf NULL oder null zu prüfen. Der Aufruf kann außerdem errno setzen, was bei der Diagnose eines Fehlers helfen kann.
Die Parameter und Flags von mmap() verstehen
Die Argumente lauten der Reihe nach address, length, prot, flags, fd und offset:
addressist eine vorgeschlagene Startadresse. MitNULLkann der Kernel eine geeignete Adresse auswählen; Anwendungen überlassen ihm dies üblicherweise.lengthgibt die Anzahl der abzubildenden Bytes an. Der Kernel berücksichtigt die Seitenausrichtung des abgebildeten Bereichs. Verwenden Sie beim Freigeben dennoch durchgehend die angeforderte Länge.protlegt die Zugriffsrechte fest. Kombinieren SiePROT_READundPROT_WRITEfür Daten, die gelesen und geändert werden sollen. Fügen SiePROT_EXECnur hinzu, wenn ausführbarer Speicher benötigt wird.flagslegen fest, wie die Abbildung gemeinsam genutzt und hinterlegt wird.MAP_PRIVATEhält Änderungen auf den jeweiligen Prozess beschränkt;MAP_SHAREDmacht sie über die gemeinsame Abbildung sichtbar.MAP_ANONYMOUSerstellt Speicher ohne Dateihinterlegung. Dieses Flag wird üblicherweise mit einem der Flags für die gemeinsame Nutzung kombiniert.fdbezeichnet bei einer dateigestützten Abbildung eine Datei. BeiMAP_ANONYMOUSwird der Deskriptor auf gängigen Unix-ähnlichen Systemen ignoriert; Beispiele verwenden oft-1.offsetbestimmt das Startbyte in einer Datei. Bei dateigestützten Abbildungen muss dieser Wert ein Vielfaches der Systemseitengröße sein. Für eine anonyme Abbildung verwenden Sie null.
Vermeiden Sie MAP_FIXED, sofern Sie keinen konkreten und sorgfältig kontrollierten Bedarf an einer bestimmten Adresse im Adressraum haben: Das Flag kann vorhandene Abbildungen im angegebenen Bereich ersetzen. Diese Flags und fork() sind auf vielen Unix-ähnlichen Systemen verfügbar, jedoch nicht in jeder C-Umgebung.
In anonymen Speicher mit mmap() schreiben
Dieses vollständige Beispiel bildet Speicherplatz für fünf Ganzzahlen ab, schreibt die Werte, liest sie aus und gibt anschließend genau den angeforderten Bereich frei. Es setzt ein Unix-ähnliches System mit Unterstützung für MAP_ANONYMOUS voraus. Bei erfolgreicher Ausführung gibt es die unten gezeigte Ausgabe aus.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
#include <stdio.h>
#include <sys/mman.h>
int main(void) {
const size_t count = 5;
const size_t length = count * sizeof(int);
int *values = mmap(NULL, length, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (values == MAP_FAILED) {
perror("mmap");
return 1;
}
for (size_t i = 0; i < count; ++i) {
values[i] = (int)(i * 10);
}
for (size_t i = 0; i < count; ++i) {
printf("[%d] ", values[i]);
}
putchar('\n');
if (munmap(values, length) == -1) {
perror("munmap");
return 1;
}
return 0;
}
[0] [10] [20] [30] [40]
Die Abbildung ist beschreibbar, weil ihre Schutzrechte PROT_READ und PROT_WRITE kombinieren. MAP_PRIVATE eignet sich hier, da kein anderer Prozess die Schreibvorgänge sehen muss. munmap() benötigt die Adresse der Abbildung und dieselbe angeforderte Länge; die Anzahl der Elemente genügt nicht. Das Beispiel gibt die Werte mit Klammern aus; die Zahlen entsprechen den geschriebenen Werten. Zeichenketten, die bei Fehlern erscheinen können, bleiben im unveränderten Beispielcode Englisch.
Eine anonyme Abbildung zwischen Prozessen gemeinsam nutzen
Eine mit MAP_SHARED erstellte Abbildung kann Änderungen über fork() hinweg übertragen. Anschließend greifen Kind- und Elternprozess auf denselben abgebildeten Bereich zu. Das Beispiel leert den Ausgabepuffer vor fork(), damit die erste Zeile bei umgeleiteter Ausgabe nicht doppelt erscheint. Der Elternprozess wartet auf das Kind, bevor er dessen Änderungen liest. Wie das vorherige Beispiel setzt auch dieses Unix-ähnliche Unterstützung für MAP_ANONYMOUS und fork() voraus. Die bereitgestellte Ausführung erzeugte die unten gezeigte Ausgabe.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
const size_t count = 5;
const size_t length = count * sizeof(int);
int *values = mmap(NULL, length, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (values == MAP_FAILED) {
perror("mmap");
return 1;
}
for (size_t i = 0; i < count; ++i) {
values[i] = (int)(i + 7);
}
printf("Initial values:");
for (size_t i = 0; i < count; ++i) {
printf(" %d", values[i]);
}
putchar('\n');
fflush(stdout);
pid_t child_pid = fork();
if (child_pid == -1) {
perror("fork");
munmap(values, length);
return 1;
}
if (child_pid == 0) {
for (size_t i = 0; i < count; ++i) {
values[i] *= 5;
}
if (munmap(values, length) == -1) {
_exit(1);
}
_exit(0);
}
int status;
if (waitpid(child_pid, &status, 0) == -1) {
perror("waitpid");
munmap(values, length);
return 1;
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
fputs("child process failed\n", stderr);
munmap(values, length);
return 1;
}
printf("Updated values:");
for (size_t i = 0; i < count; ++i) {
printf(" %d", values[i]);
}
putchar('\n');
if (munmap(values, length) == -1) {
perror("munmap");
return 1;
}
return 0;
}
Initial values: 7 8 9 10 11
Updated values: 35 40 45 50 55
Das Kind schreibt in die gemeinsam genutzte Abbildung und wird beendet. Sobald waitpid() abgeschlossen ist, liest der Elternprozess dieselben Änderungen. Eine Abbildung mit MAP_PRIVATE würde dieses gemeinsame Nutzungsverhalten nicht ermöglichen. Beide Prozesse geben ihre jeweilige Abbildung vor dem Beenden frei. Bei dateigestützten Abbildungen kann MAP_SHARED Änderungen über die Abbildung sichtbar machen; die dauerhafte Speicherung in der Datei hängt jedoch zusätzlich von Synchronisierung und dem Dateisystem ab. Die Ausgabebezeichnungen „Initial values:“ und „Updated values:“ bleiben im bytegleich übernommenen Beispielcode Englisch.