C-Funktionen nach C++ portieren und instanziieren
-
das C++ Programm ist ein MDI-Framework (weniger wichtig).
Ich erzeuge eine Emulator-Instanz (der Emulator-Klasse) und dieses Objekt startet derzeit die main() des C-Projekts und visualisiert ein paar Daten des C-Projekts in einem Window:In diesem C-Projekt sind natürlich Datenfelder definiert (structs, Variablen, ...).
Wenn ich jetzt eine 2. Emulator-Instanz starte, die dann wieder die main()-Methode des C-Projekts aufruft, greift diese auf dieselben Daten des C-Projekts zu, wie das zuerst erzeugte Objekt.
Das soll aber so nicht sein...Jetzt bin ich auf der Suche nach einer einfachen Lösung, ohne mein C-Projekt nach C++ portieren zu müssen.
-
Entweder verstehe ich da gerade etwas anders als du es meinst oder du hast da den Oberbug aller Zeiten gefunden. Daher vermutlich ersteres. Wie rufst du das C-Programm denn auf? Heißt das etwa, dass das C-Programm kein eigenes Programm ist, sondern in dein C+-Programm eincompiliert wird? Falls letzteres: Tja, so ist das nun einmal, wenn man Nicht-Reentrant-Code mehrmals parallel aufruft. Liegt dann irgendwo zwischen "Selbst schuld!" und "Was hast du erwartet?".Allgemeine Abhilfe wäre jedenfalls, das C-Programm in einem eigenen Prozess laufen zu lassen, statt in einem Thread, wie du es anscheinend jetzt machst. Wie das mit Prozessen&Co geht, ist jedoch stark betriebssystemabhängig, da müsstest du uns deine Plattform verraten.
-
natürlich "selbst schuld" 
ich compiliere das C-Projekt in das C++-Projekt, um im Emulator besser weiterentwickeln zu können.
nun wollte ich das ganze eben soweit erweitern, dass mehrere "C-Projekt"-Instanzen parallel laufen.Du hast richtig eingeschätzt, dass ich das ganze derzeit in einem Thread laufen lasse, um auf die Daten (Visualisierung) zugreifen zu können.
Würde das bei einem Prozess auch noch gehen? Wohl nicht direkt oder?Meine Plattform ist Windows (hier Win7), Visual Studio 2008 und 2010
-
Wenn das C-Programm von globalen Daten abhängt, wird das nicht möglich sein, da es von denen innerhalb deiner exe eben nur eine Instanz gibt...
-
Das C-Programm hat "intern" globale Daten,
genau diese hätte ich gerne aber in meinem C++-Tool instanziiert.Gibt es da keine Möglichkeit?
-
jcp1978 schrieb:
Gibt es da keine Möglichkeit?
Gibt es: Das C Programm so umschreiben, dass es eben keine globalen Daten verwendet.
-
jcp1978 schrieb:
Gibt es da keine Möglichkeit?Gibt es: Das C Programm so umschreiben, dass es eben keine globalen Daten verwendet.
das scheidet leider aus
das C-Programm läuft so wie es ist auf einem Mikroprozessor,
da macht es wenig Sinn, das dort zu ändern.
-
Wieso musst du eigentlich im selben Prozess mehrere "Instanzen" dieses C-Programms haben?
-
Weil dann der Datenaustausch ziemlich einfach zu realisieren ist/wäre.
Im Mikroprozessor kommunizieren die "C-Prozesse" jeweils über CAN.
Hier in meinem Emulator wäre es einfach den CAN-Bus zu simulieren und die einzelen Instanzen untereinander zu "verbinden".
Das wäre zwar auch zwischen Prozessen möglich, aber ich denke nicht ganz so einfach...
-
Es wäre wohl nicht ganz so einfach, dafür aber überhaupt erstmal möglich

-
ich hatte da bei einem anderen Projekt schonmal mit SharedMem zu tun, das ist nicht das Problem...
eher, es ist einfacher n Threads zu verwalten, als n Prozessedeshalb mein Ansatz, aber scheinbar leider eine Sackgasse

-
Naja, es ist technisch nicht unmöglich. Aber wenn du das C-Programm nicht verändern kannst (man könnte einen Metacompiler schreiben der das C-Programm eben in eine C++ Klasse wrapped oder zumindest globale Variablen threadlocal macht, sodass man dann eben pro Instanz einen Thread hat), dann sind mehrere Prozesse wohl die einfachste Lösung. Wenn du für die Kommunikation sowieso einen Bus modellieren willst, dann dürfte das z.B. über Pipes wohl auch nicht so besonders kompliziert zu implementieren sein.
-
wie würde so ein wrapper in etwa aussehen?
-
Na so wie dein C++ Programm ihn haben will^^
-
Interprozesskommunikation ist keine Raketenwissenschaft. Es ist nicht ganz so einfach wie Interthreadkommunikation, aber nicht vor dem man Berührungsängste haben müsste. Pipes wurden dir schon genannt, wenn du es eine Portion abstrakter haben möchtest, kannst du dir ja mal MPI angucken.
-
jcp1978 schrieb:
Das C-Programm hat "intern" globale Daten,
genau diese hätte ich gerne aber in meinem C++-Tool instanziiert.Gibt es da keine Möglichkeit?
Jain.
Du kannst jedes deiner C-Projekte zu einer DLL compilieren.
Dann kannst du unterschiedliche C-Projekte (=unterschiedliche DLLs) nebeneinander laufen lassen. Jede DLL hat eigene Kopien globaler Variablen, also ist alles gut.Was damit nicht geht: du kannst so nicht mehrere Instanzen des selben C-Projekts in deinem Emulator laufen lassen. Die globalen Variablen eines einzelnen Projekts sind ja immer noch nur 1x vorhanden.
Wobei man selbst das mit einem Trick (Hack) umgehen könnte: schreib dir einen "Loader", der die DLL erstmal in irgendein Temp-Verzeichnis kopiert, und ihr dabei einen eindeutigen (im Sinn von "unique") Namen verpasst (GUID oder was auch immer). Die Kopie der DLL lädst du dann mit LoadLibrary.
Wenn ich mich nicht sehr sehr täusche, hätte dann wieder jede Kopie der DLL ihre eigenen globalen Variablen.
Pro Instanz eines Programms die du laufen lassen willst, müsstest du dann eine neue Kopie erzeugen und laden.Da du die DLLs dann mit LoadLibrary lädst, musst du dir alle Funktionen die du in den DLLs aufrufen willst mit GetProcAddress holen. Bei vielen Funktionen kann das viel lästig werden. Üblicherweise macht man es daher so, dass man bloss eine Funktion exportiert, die einen Zeiger auf eine Instanz einer Klasse zurückgibt, deren sämtliche Funktionen "virtual pure" sind. Diese Funktionen kannst du dann über den Zeiger aus dem Emulator-Programm aufrufen, ohne dass du sie mit LoadLibrary holen müsstest oder gar "fest" binden (=über eine import-lib).
Und je länger ich darüber nachdenke, desto besser gefällt mir dieser Hack

Sieh nur zu dass du ausreichend Kommentare schreibst was dein Emulator da macht, und vor allem wieso - damit das der nächste der das Projekt warten muss auch verstehen kann.
-
na also,
nach sowas hab ich gesucht, hatte nur noch nicht viel mit DLLs am Hut,
dann wird´s jetzt Zeit das nachzuholen...1000 Dank an alle und besonders @hustbaer
-
Ja, genau sowas in der Art wollte ich auch schon fast vorschlagen. Aber imo zahlt sich dieses gefrickel nicht wirklich aus, wenn man bedenkt, dass die einzelnen Instanzen sowieso über einen "CAN Bus" kommunizieren sollen. Das bedeutet er muss sowieso ein Bussystem nachbauen. Ob selbiges seine Daten nun durch Pipes schickt oder ob er sich selbst sowas wie Pipes baut, macht dann wohl keinen Unterschied, im Gegenteil. Evtl. ist die Variante mit mehreren Prozessen also nicht nur sauberer, sondern sogar auch noch weniger Implementierungsaufwand.
-
dot schrieb:
Evtl. ist die Variante mit mehreren Prozessen also nicht nur sauberer, sondern sogar auch noch weniger Implementierungsaufwand.
Das bezweifle ich mal stark.
Hätte aber noch andere Vorteile wenn das in verschiedenen Prozessen läuft. z.B. dass die "Systeme" dann auch wirklich weitestgehend getrennt sind, und ein Crash/krasses Fehlverhalten eines Systems (Speicher überschreiben, ...) ein anderes System nicht beeinflussen kann.
Auch könnte man einfach ausprobieren was passiert, wenn man ein System unerwartet aus dem Spiel entfernt (Taskmanager, Prozess beenden).Dafür ist es wieder lästiger in anderen Situationen. Wenn der User das Emulator-Programm beenden will, z.B. weil es sich weggehängt hat, dann muss er danach noch alle "System-Prozesse" einzeln killen. Kann man natürlich auch so machen dass die das mitbekommen und sich dann selbst beenden, aber ... auch wieder Aufwand.
-
hustbaer schrieb:
dot schrieb:
Evtl. ist die Variante mit mehreren Prozessen also nicht nur sauberer, sondern sogar auch noch weniger Implementierungsaufwand.
Das bezweifle ich mal stark.
Naja, mit dem dll-Hack muss er dann eben statt der Prozessinstanzen die einzelnen Module verwalten (abgesehen davon dass es natürlich unsauber ist, weil rumgefrickel mit temporären Dateien, der Code mehrfach gemapped wird etc.). Wenn er das prozessintern mit Threads machen will, dann muss er seinen CAN Bus immer noch selber bauen, was dann aber bedeutet er muss sich selber um die Verwaltung der Buffer und die Synchronisation kümmern. Zugegeben: Das ist jetzt auch nicht grad hochkompliziert, aber mit Pipes und separaten Prozessen braucht er all das nicht zu tun, weil es das Betriebssystem schon automatisch macht -> Nicht nur sauberer sondern auch weniger Aufwand (oder zumindest ganz sicher nicht mehr)...