Mmap gibt ein void *, aber kein volatile void*
zurück. Wenn ich den gemeinsamen Speicher mit mmap abbilde, könnte ein anderer Prozess in diesen Speicher schreiben, was bedeutet, dass zwei aufeinanderfolgende Lesevorgänge vom gleichen Speicherort unterschiedliche Werte ergeben können - die genaue Situation, für die volatile gedacht ist. Also warum gibt es keine flüchtige Leere zurück?
Meine beste Vermutung ist, dass wenn Sie einen Prozess haben, der ausschließlich in das Shared-Memory-Segment schreibt, muss er sich den flüchtigen Speicher nicht durch flüchtige Zeiger ansehen, weil er immer das richtige Verständnis davon haben wird, was vorhanden ist; Alle Optimierungen, die der Compiler durchführt, um redundante Lesevorgänge zu verhindern, spielen keine Rolle, da sonst nichts mehr die Werte unter seinen Füßen schreibt und ändert. Oder gibt es einen anderen historischen Grund? Ich bin geneigt zu sagen, dass die Rückgabe von volatile void*
ein sicherer Standard wäre, und diejenigen, die diese Optimierung wünschen, könnten dann manuell in void * umwandeln.
POSIX mmap Beschreibung: Ссылка
Die tief verwurzelte Annahme, die viele Softwaresysteme durchläuft, ist, dass die meisten Programmierer sequentielle Programmierer sind. Dies hat sich erst seit kurzem geändert.
mmap
hat Dutzende von Verwendungen, die nicht mit dem gemeinsamen Speicher zusammenhängen. Für den Fall, dass ein Programmierer ein Multithread-Programm schreibt, müssen sie ihre eigenen Schritte unternehmen, um die Sicherheit zu gewährleisten. Der Schutz der einzelnen Variablen mit einem Mutex ist nicht standardmäßig. Ebenso nimmt mmap
nicht an , dass ein anderer Thread strittige Zugriffe auf dasselbe Shared-Memory-Segment durchführt, oder sogar, dass ein so zugeordnetes Segment für einen anderen Thread zugänglich ist.
Ich bin auch nicht davon überzeugt, dass die Markierung von mmap
als volatile
sich darauf auswirken wird. Ein Programmierer müsste immer noch die Sicherheit beim Zugriff auf die gemappte Region gewährleisten, nein?
Das Implementieren von gemeinsam genutztem Speicher ist nur eine kleine Teilmenge der Verwendungen von mmap()
. Die am häufigsten verwendeten Anwendungen sind das Erstellen von privaten Mappings, sowohl anonym als auch dateiunterstützt. Dies bedeutet, dass selbst dann, wenn wir Ihre Behauptung akzeptieren, dass ein volatile
-qualifizierter Zeiger für den Zugriff auf gemeinsamen Speicher erforderlich ist, solch ein Qualifikationsmerkmal im allgemeinen Fall überflüssig wäre.
Denken Sie daran, dass Sie endgültige Qualifizierer immer zu einem Zeigertyp ohne Casting hinzufügen können, aber Sie können sie nicht entfernen. Mit der aktuellen mmap()
-Deklaration können Sie also beides tun:
und das:
%Vor%Mit Ihrem Vorschlag müssten die Benutzer im gemeinsamen Fall das flüchtige Objekt ablegen.
Flüchtigkeit würde nur einen einzigen Lesevorgang abdecken (was je nach Architektur 32 Bit oder etwas anderes sein kann und daher ziemlich einschränkend sein kann. Oft müssen Sie mehr als 1 Maschinenwort schreiben, und Sie werden es sowieso tun um eine Art Locking einzuführen.
Selbst wenn es flüchtig wäre, könnten Sie leicht zwei Prozesse haben, die unterschiedliche Werte aus dem gleichen Speicher lesen. Es braucht nur einen 3. Prozess, um in den Speicher in der Nanosekunde zwischen dem Lesen vom 1. Prozess und dem Lesen zu schreiben aus dem 2. Prozess (es sei denn, Sie können garantieren, dass die 2 Prozesse denselben Speicher innerhalb fast derselben Taktzyklen lesen.
Also - es ist ziemlich nutzlos für mmap (), mit diesen Dingen umzugehen, und es ist besser dem Programmierer überlassen, mit dem Speicherzugriff umzugehen und den Zeiger als flüchtig zu markieren, wo es gebraucht wird - wenn der Speicher geteilt wird - Sie werden müssen alle beteiligten Parteien kooperativ und bewusst sein, wie sie das Gedächtnis in Bezug zueinander aktualisieren können - etwas außerhalb des Umfangs von mmap, und etwas, das Volatium nicht lösen wird.
Ich glaube nicht, dass volatile
tut, was Sie denken.
Im Grunde sagt es nur dem Compiler, die Variable nicht zu optimieren, indem sie ihren Wert in einem Register speichert. Dies zwingt ihn, den Wert jedes Mal abzurufen, wenn Sie darauf verweisen, was eine gute Idee ist, wenn ein anderer Thread (oder was auch immer) es in der Zwischenzeit aktualisiert haben könnte.
Die Funktion gibt ein void * zurück, aber es wird nicht aktualisiert, daher ist das Aufrufen von volatile bedeutungslos. Selbst wenn Sie den Wert einem lokalen flüchtigen void * zuweisen würden, würde nichts gewonnen.
Der Typ volatile void *
oder void * volatile
ist unsinnig: Sie können eine void *
nicht dereferenzieren, daher ist es nicht sinnvoll, Typqualifizierer anzugeben.
Und da Sie sowieso eine Umwandlung in char *
oder Ihren Datentyp benötigen, ist dies vielleicht der richtige Ort, um die Volatilität anzugeben. Daher ist die API, wie sie definiert wurde, eine gute Seite, um die Verantwortung für das Markieren des Speichers zu ändern, der veränderbar / flüchtig ist.
Das heißt, von einem großen Bild POV, stimme ich Ihnen zu: mmap sollte einen Rückgabetyp haben, der besagt, dass der Compiler diesen Bereich nicht zwischenspeichern sollte.
Das ist wahrscheinlich aus Performance-Gründen so gemacht worden und bietet standardmäßig nichts extra. Wenn Sie wissen, dass in Ihrer speziellen Architektur Schreib- / Lesevorgänge nicht vom Prozessor neu angeordnet werden, benötigen Sie möglicherweise keine flüchtigen Funktionen (möglicherweise in Verbindung mit einer anderen Synchronisierung). BEARBEITEN: Dies war nur ein Beispiel - es gibt eine Vielzahl anderer Fälle, in denen Sie wissen, dass Sie nicht jedes Mal, wenn auf den Speicher zugegriffen wird, ein erneutes Lesen erzwingen müssen.
Wenn Sie sicherstellen müssen, dass bei jedem Zugriff alle Adressen aus dem Speicher gelesen werden, wird const_cast (oder C-Style-Umwandlung) automatisch auf den Rückgabewert gesetzt.