So teilen Sie Speicher zwischen in C / C ++ geschriebenen Anwendungen

9

Ich gehe durch ein in C / C ++ geschriebenes Programm zur Steuerung in der Robotik. Grundsätzlich werden drei verschiedene Programme gleichzeitig ausgeführt und kommunizieren über den gemeinsamen Speicher. Beim Google-Herumdenken fand ich, dass vxWorks und die Interprozess-Header der Boost-Bibliotheken ( Boost-Dokumentation: Speicher zwischen Prozessen teilen ).

Jetzt möchte ich nicht auf die Implementierung schauen, ich kann den obigen Link lesen. Aber ich kann mir nicht vorstellen, wie die Boost-Bibliothek das macht. Ich meine, eine Anwendung weist Speicher zu und andere greifen auf diesen Speicher zu, aber wie kommunizieren sie? Ist es nicht unsicher, dies zu tun?

cauchy
quelle
Was sieht in den von Ihnen genannten Dokumenten unklar aus? "Wenn Sie Objekte in einem zugeordneten Bereich platzieren und diesen Bereich in jedem Prozess an einer anderen Adresse zuordnen, sind Rohzeiger ein Problem, da sie nur für den Prozess gültig sind, der sie dort platziert hat. Um dies zu lösen, bietet Boost.Interprocess einen speziellen intelligenten Zeiger an kann anstelle eines Rohzeigers verwendet werden. Daher können Benutzerklassen, die Rohzeiger enthalten (oder Boost-Smart-Zeiger, die intern einen Rohzeiger besitzen), nicht sicher in einem gemeinsam genutzten Prozessbereich platziert werden. Diese Zeiger müssen durch ... ersetzt werden. "
Mücke
Vergessen Sie nicht, dass das Betriebssystem der Prozess ist, der sich tatsächlich um den Speicher kümmert. Die Prozesse, die den Speicher am Ende des Tages zuweisen und verwenden, verwenden das Betriebssystem, um ihre Anforderungen zu stellen. Das Betriebssystem verwaltet die Mehrfachverarbeitung und stellt sicher, dass keine Konflikte auftreten.
Rob Sedgwick
@gnat Die Implementierung ist klar. Wie macht Boost diese Implementierung nicht in diesen Dokumenten ... Ich möchte sie nicht replizieren (das wäre absurd), sondern verstehen.
Cauchy

Antworten:

11

Aber ich kann mir nicht vorstellen, wie die Boost-Bibliothek das macht.

Der Boost-Interprozess-Mechanismus besteht aus drei erforderlichen Komponenten:

  1. Speicherzuordnungsdatei: Eine Speicherzuordnungsdatei muss erstellt und an einen Boost.interprocess-Allokator übergeben werden. Dieser Allokator nimmt Teile der Datei und verwendet sie so, als ob sie von einem std :: allocator zurückgegeben würden, wobei die Zuordnung angewendet wird, damit der Speicher mit dem prozessspezifischen Speicher kompatibel ist.

  2. boost.interprocess container; Diese Art von Container verwendet den vom Allokator zurückgegebenen Speicher und bietet eine std :: container-ähnliche Schnittstelle (begin / end / size / push_back usw.).

  3. Synchronisationsmechanismus; Dies kann ein beliebiger Interprozess-Mutex sein und sollte verwendet werden, um Datenzugriffsbedingungen zu verhindern.

Ich meine, eine Anwendung weist Speicher zu und andere greifen auf diesen Speicher zu, aber wie kommunizieren sie? Ist es nicht unsicher, dies zu tun?

Der zugewiesene Speicher ist tatsächlich eine gemeinsam genutzte Speicherzuordnungsdatei. Die Kommunikation erfolgt indirekt, wobei beide Anwendungen die Daten nach Bedarf einstellen oder lesen. Die Sicherheit ergibt sich aus der Verwendung von Interprozess-Synchronisationsprimitiven.

utnapistim
quelle
2
Bemerkenswert: Alle drei dieser IPC-Mechanismen erfordern Kernel-Unterstützung. Für diejenigen, die neugierig sind, wie dies gemacht wird (wie im OP angegeben), kann dies nicht nur von einzelnen Anwendungen durchgeführt werden. Die Anwendungen müssen den Kernel auffordern, die Dateien im Speicher zuzuordnen oder mit anderen Prozessen zu synchronisieren.
Cort Ammon
5

Shared Memory ist nicht das vollständige Bild für IPC, sondern ein Datenübergabemechanismus. Sie müssen jedoch den anderen Prozess darüber informieren, dass einige Daten aktualisiert wurden und zum Lesen verfügbar sind. Wie Sie dies tun, liegt bei Ihnen. Normalerweise verwenden Sie einen Betriebssystem-Mutex oder ein Ereignisobjekt. Jeder Prozess wartet darauf, dass dies festgelegt wird. Das Schreiben der Anwendung legt es fest, sobald das Schreiben abgeschlossen ist. Dann werden Threads in den anderen Programmen aktiviert und gelesen.

Alternativ können Sie die Daten regelmäßig abfragen, um einen Wert zu finden, der sich ändert, wenn die Daten aktualisiert werden (z. B. einen inkrementierenden Zähler).

gbjbaanb
quelle
4

Boost verwendet die Speicherzuordnung einer Datei.

Sowohl Unix als auch Windows unterstützen die Erstellung von Dateien, die im normalen Dateisystem nicht vorhanden sind.

Dann müssen Sie den Zugriff auf diesen Speicher so synchronisieren, wie Sie es tun würden, wenn verschiedene Threads darauf zugreifen würden. Das bedeutet, dass gleichzeitige Lesevorgänge ohne Synchronisierung erfolgen können. Sobald jedoch ein Prozess schreiben möchte, müssen Sie verhindern, dass die anderen darauf zugreifen.

Atomische Operationen im gemeinsam genutzten Speicher sind weiterhin möglich, wenn Sie eine sperrenlose Synchronisation wünschen.

Ratschenfreak
quelle
Können Sie bitte erläutern, dass "Atomic-Operationen im gemeinsam genutzten Speicher weiterhin möglich sind, wenn Sie eine sperrenlose Synchronisierung wünschen"? Sie möchten damit sagen, dass Sie, wenn jedes Programm C ++ ist, die C ++ 11- std::atomicVorlagenklasse ( cplusplus.com/reference/atomic ) in jedem der beiden Programme verwenden müssen, damit sie in den gemeinsam genutzten Bereich schreiben können ohne Synchronisation über Sperren erzwungen?
Gabriel Staples
@ GabrielStaples ja oder die äquivalente atomare Intrinsik
Ratschenfreak
Entschuldigen sie die erneute Störung; Ich bin nicht mit "atomaren Intrinsics" vertraut. Können Sie mich bitte auf eine Referenz verweisen, um sie genauer zu studieren? Eine schnelle Google-Suche ist unklar.
Gabriel Staples
3

Shared Memory ist immer noch nur Speicher. Sie können dort einen Mutex, einen Spinlock oder ein anderes Synchronisationsprimitiv einfügen und damit den Zugriff Ihrer Prozesse auf den gemeinsam genutzten Speicher synchronisieren, genau wie Threads diese Primitive verwenden, um den Zugriff auf den für sie sichtbaren Speicher zu synchronisieren.

Die einzigen wirklichen Unterschiede sind:

  1. Threads teilen sich den gesamten Speicher und den gleichen Adressraum, sodass rohe Zeiger für sie funktionieren. Der von den Prozessen gemeinsam genutzte Speicher funktioniert genauso, kann jedoch in jedem Prozess an verschiedenen Adressen zugeordnet werden, sodass Sie nicht einfach Rohzeiger zwischen ihnen übergeben können

    • NB. Dies wirkt sich auf einige Implementierungsdetails virtueller Methoden, Laufzeittypinformationen und einige andere C ++ - Mechanismen aus. Halten Sie sich an trivial initialisierbare Typen (einfache alte Daten) ohne virtuelle Methoden oder dynamische Umwandlungen in Ihrem gemeinsam genutzten Speicher, verwenden Sie keine Typ-ID für sie, und es sollte Ihnen gut gehen.
  2. Einige Synchronisationsprimitive benötigen möglicherweise spezielle Flags oder Attribute, um zwischen Prozessen ordnungsgemäß zu funktionieren (siehe beispielsweise das PTHREAD_PROCESS_SHAREDAttribut für POSIX-Thread-Mutexe). Dies hat nicht wirklich mit dem Speicher und der Synchronisation an sich zu tun, sondern mit der Kernel / Scheduler-Interaktion, die erforderlich ist, um schlafende Kellner aufzuwecken.


Damit:

aber wie kommunizieren sie?

Auf die gleiche Weise kommunizieren verschiedene Threads, wobei die oben genannten Einschränkungen berücksichtigt werden

Ist es nicht unsicher, dies zu tun?

Ja, die Kommunikation von Prozessen über den gemeinsam genutzten Speicher ist genauso unsicher wie die Kommunikation von Threads über den gemeinsam genutzten Speicher. Sie benötigen eine gleichwertige (oder identische) Synchronisierung, um die Sicherheit zu gewährleisten.

Nutzlos
quelle
3

Beachten Sie, dass C und C ++ unterschiedliche Sprachen sind.

Shared Memory ist in reinem Standard C11 oder C ++ 11 (da der Standard dies nicht definiert) oder sogar in C ++ 14 (dessen Entwurf n3690 und vermutlich offizieller Standard Shared Memory außerhalb von Multithreading nicht erwähnt) nicht möglich ). Sie benötigen also zusätzliche Bibliotheken, um gemeinsam genutzten Speicher zu erhalten. Einige Betriebssysteme unterstützen jedoch gemeinsam genutzten Speicher. Es gibt also mehrere Bibliotheken, die gemeinsam genutzten Speicher bereitstellen und auf vorhandenen Betriebssystemdiensten aufbauen. Sie könnten vielleicht in Betracht ziehen, die POCO- Framework-Bibliothek zu verwenden (die über betriebssystemspezifische Details abstrahiert).

Schauen Sie sich für Linux (und möglicherweise POSIX) shm_overview (7) an . Sie müssen synchronisieren, siehe auch sem_overview (7)

VXWorks (das ich nicht kenne, aber gegoogelt habe) hat VxMP

Sie müssen sorgfältig verstehen, was wirklich passiert. Sie möchten wahrscheinlich nur einfache alte Daten struct-s (keine C ++ - Klassen!) Freigeben und sollten sehr vorsichtig mit den Adressen (jeder Prozess erhält möglicherweise eine andere Adresse für das gemeinsame gemeinsam genutzte Speichersegment) und der Synchronisation sein.

Alternativ können Sie Threads verwenden. Beachten Sie, dass der C ++ 11-Standard eine Thread-Bibliothek definiert .

Basile Starynkevitch
quelle
1
Natürlich ist dieser gemeinsame Speicher sowohl in C ++ 11 als auch in C11 möglich! Die Tatsache, dass es kein Teil des Standards ist, ist bedeutungslos. Die grafische Benutzeroberfläche ist auch kein Teil des Standards. Es gibt mehrere Bibliotheken, einige plattformübergreifende , die es einem ermöglichen, gemeinsam genutzten Speicher und verschiedene Synchronisationsmethoden zu verwenden ...
AK_
1
Mein Punkt war, dass Shared Memory nicht durch den C ++ 11-Standard definiert ist (aber einige Implementierungen haben sie über
betriebssystemspezifische
Ich denke, Sie sollten sich Zeit nehmen, um zu verstehen, was der Begriff "Sprachstandard" tatsächlich bedeutet, was eine standardkonforme Implementierung ist und was eine Bibliothek ist.
AK_
Bitte verweisen Sie mich auf den Abschnitt im C ++ 11-Standard (oder im n3690-Entwurf von C ++ 14), in dem es um gemeinsam genutzten Speicher geht.
Basile Starynkevitch
3
Ich denke, wir sind uns beide einig, aber wir sind uns vielleicht nicht einig darüber, was Standard C ++ 11 bedeutet. Für mich ist es genau (nicht mehr als) der ISO C ++ 11-Standard (oder der dazu entsprechende freie Entwurf). Externe Bibliotheken zählen nicht als Standard, auch wenn sie allgemein und plattformübergreifend sind.
Basile Starynkevitch