C-Funktionen nach C++ portieren und instanziieren
-
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)...
-
Nein.
Da CAN ein multidrop, multi-master Bus ist, wird er soweiso etwas selbst implementieren müssen. Und wieso sollte das mit Prozessgrenze einfacher sein als ohne? Wo hilft sie mir?
Falls Sockets/Pipes wirklich hilfreich sein sollten, dann kann man diese genau so gut innerhalb eines Prozesses verwenden. Verbietet ja keiner. Abgesehen davon dass ich nicht wüsste was damit besser gehen sollte.Und je genauer er das Verhalten eines echten CAN Bus (z.B. Kollisionen/Arbitration) nachbilden will, desto eher wird er froh sein dass er keine lästige Prozessgrenze hat die bloss überall stört.
abgesehen davon dass es natürlich unsauber ist, weil rumgefrickel mit temporären Dateien, der Code mehrfach gemapped wird etc.
Sorry, aber das ist nur blah.
Dass der Code mehrfach gemappt wird ist jetzt genau 100% egal. Und seit wann ist mit Temp-Files arbeiten unsauber?
-
hustbaer schrieb:
Da CAN ein multidrop, multi-master Bus ist [...]
Das stimmt, dafür eignen sich Pipes nicht wirklich, da hast du absolut Recht.
hustbaer schrieb:
Und wieso sollte das mit Prozessgrenze einfacher sein als ohne? Wo hilft sie mir?
Nun, ich ging davon aus, dass er sowieso sowas wie Pipes oder Sockets wird verwenden wollen. In dem Fall wär die Lösung mit mehreren Prozessen auf jeden Fall ganz sicher nicht aufwändiger. Allerdings war das natürlich ein Denkfehler meinerseits.
hustbaer schrieb:
abgesehen davon dass es natürlich unsauber ist, weil rumgefrickel mit temporären Dateien, der Code mehrfach gemapped wird etc.
Sorry, aber das ist nur blah.
Dass der Code mehrfach gemappt wird ist jetzt genau 100% egal. Und seit wann ist mit Temp-Files arbeiten unsauber?Nun, dass der Code mehrfach gemapped wird ist einfach unschön, natürlich ist es jetzt kein wirkliches Problem oder so. Mir fällt jetzt auch kein rein objektives Argument gegen diese Lösung ein, wie gesagt, ich persönlich finds einfach nicht besonders "schön". Funktionieren tuts sicher...