Entwickler-Ecke
Sonstiges (Delphi) - Multithreading mit DLL-Klassen-zugriff
Aya - Di 24.10.06 22:57
Titel: Multithreading mit DLL-Klassen-zugriff
Hi,
ich habe ein mehr oder weniger verzwicktes problem.. zur erklärung muß ich ein wenig weiter ausholen :)
(Der Code an sich ist alles nur auf das minimalste beschränkt.. also nicht wundern wenn irgendwo ein Create oder ähnliches fehlt)
Ich schreibe ein programm welches eine Bild-sequenz darstellen soll.
Der user bekommt eine Zeitleiste angezeigt, und wenn er durch diese durchscrollt wird das entsprechende bild geladen + angezeigt.
Aus performance gründen Cache ich alle Bilder in einem Array of TBild (TBild ist ein Array mit Höhe * Breite * 4 of Byte) in einem extra Thread vor, was auch prima klappt.
Der Thread macht nichts anderes als die Bilder zu laden und in den Cache-Array zu schreiben.
Es kann nun aber auch vorkommen, das 2 oder mehr Cache-Threads gleichzeitig laufen, sprich die Sequenz an mehreren stellen gleichzeitig gecacht wird. Auch das funktioniert dank Synchronize/CritialSection wunderbar..
Und nun zu dem Problem:
Um x-beliebig viele Bildformate zu unterstützen habe ich die funktion für's laden in DLLs ausgelagert. Und nachdem eine DLL ja leider nur Integer's etc zurückgeben kann, und keine Bitmaps oder Dynamische Arrays, erstelle ich in der DLL eine Klasse welche vom Hauptprogramm verwendet werden kann:
Delphi-Quelltext
1: 2: 3: 4:
| TDLLClass = class Image: TBild; procedure loadImage(Filename: PChar); end; |
die procedure loadImage lädt also das Bild und schreibt es in "Image". Der aufruf im Thread sieht dann etwa so aus:
Delphi-Quelltext
1: 2:
| DLLClass.loadImage('...'); Cache.Add(Frame, DLLClass.Image); |
und das klappt ebenfalls wunderbar, allerdings nur solange es nur ein Thread ist...
Kommt jetzt ein zweiter Thread hinzu, überschneiden sich logischerweise die zugriffe auf die "Image"-Variable in der TDLLClass...
Und das ist die stelle wo ich ein wenig hänge grad... klar, ich könnte die Variable auch mit Synchronize/CriticalSections schützen, allerdings geht in dem Moment der sinn der Threads verloren, weil immer nur einer gleichzeitig auf die Image-Variable zugreifen könnte = nur ein Thread etwas cachen könnte..
Hat jemand eine Idee wie ich das problem lösen könnte?
Oder weiß jemand eine andere möglichkeit das Image was loadImage lädt aus der DLL in das Hauptprogramm zu bekommen?
Au'revoir,
Aya~
PS: Die DLL muß kompatibel zu VC++ bleiben!
alias5000 - Di 24.10.06 23:17
Ich bin mir nicht sicher, ob ichs vollständig verstanden habe, aber könnte es evtl. gehen, wenn du für jeden Thread eine eigene Instanz von TDLLCache erzeugst? Dann greifen die nicht mehr parallel auf eine Instanz zu...
Oder du machst aus loadimage ne Function und gibst als Rückgabewert das TBild zurück, dann würde die eine Variable entfallen. Aber ob das funktioniert, weiß ich nicht, da die Frage ist, was passiert, wenn zwei Threads parallel eine Funktion ausführen (da fehlt mir einfach die Erfahrung ;) )
Gruß alias5000
Aya - Di 24.10.06 23:20
Hi,
die sache mit mehreren Instanzen hatte ich auch überlegt, ist aber sehr sehr sehr ungünstig.. (wegen anderen sachen die noch passieren in der DLL Klasse).
Das mit der funktion und rückgabe.. das hatte ich irgendwie überhaupt nicht bedacht.. :shock: Rein von der logik her seh ich so spontan keinen grund warum das nicht klappen sollte, werd ich mal testen :)
Aya~
tommie-lie - Di 24.10.06 23:25
Titel: Re: Multithreading mit DLL-Klassen-zugriff
Aya hat folgendes geschrieben: |
Um x-beliebig viele Bildformate zu unterstützen habe ich die funktion für's laden in DLLs ausgelagert. Und nachdem eine DLL ja leider nur Integer's etc zurückgeben kann, und keine Bitmaps oder Dynamische Arrays |
Wie wäre es mit Pointern? :zwinker:
Zitat: |
erstelle ich in der DLL eine Klasse welche vom Hauptprogramm verwendet werden kann:
Delphi-Quelltext 1: 2: 3: 4:
| TDLLClass = class Image: TBild; procedure loadImage(Filename: PChar); end; |
die procedure loadImage lädt also das Bild und schreibt es in "Image". Der aufruf im Thread sieht dann etwa so aus:
Delphi-Quelltext 1: 2:
| DLLClass.loadImage('...'); Cache.Add(Frame, DLLClass.Image); | |
Und das geht ohne COM und ist immer noch mit VC++ kompatibel?
Zitat: |
Hat jemand eine Idee wie ich das problem lösen könnte?
Oder weiß jemand eine andere möglichkeit das Image was loadImage lädt aus der DLL in das Hauptprogramm zu bekommen? |
Gegenvorschlag zu deinem bisherigen Vorgehen:
Die DLL exportiert eine Funktion LoadImage(Filename: PChar; out Width: LongWord; out Height: LongWord; out Data: PLongWord), die das Bild inklusive Informationen an das Hauptporogramm zurückliefert. Nach Width und Height wird die Breite und Höhe gespeichert, in Data kommen die Bildinformationen in einem vorher festzulegenden Bildformat. Ich hätte hier an ein Zeilenverfahren gedacht, in dem Zeile für Zeile ein LongWord pro Pixel gespeichert wird, wenn du da irgendwie ein dreidimensionales Array draus gebastelt hast kann entweder das Hauptprogramm die Daten umwandeln oder die DLL legt sie gleich richtig im Speicher ab. Ein dynamisches Array wäre das dann zwar nicht mehr unbedingt, aber man kann sich ja mit einem
type TPixelArray: array[0..0] of TPixel; type PPixelArray: ^TPixelArray; behelfen, wenn man nur selten großartig an den Bildern rumschnippeln muss. Das Verfahren sollte ganz ohne Critical Sections thread-safe sein, sofern die einzelnen Funktionen für sich thread-safe sind (also die DLL intern nicht irgendwas böhses[tm] anstellt), vom gemeinsam verwalteten Bilder-Cache mal abgesehen, aber der ist ja so oder so nicht thread-safe.
Aya - Di 24.10.06 23:42
Hi,
das problem bei der sache wie du sie beschreibst ist, dsa ich in der DLL speicher für die Bilddaten reservieren müßte, was aber nicht geht (zumindest ist er bei mir immer abgeschmiert sobald ich das versucht habe) :(
Ich versuch jetzt erstmal das mit der function, vieleicht klappt das ja schon :)
Aya~
tommie-lie - Di 24.10.06 23:52
Aya hat folgendes geschrieben: |
das problem bei der sache wie du sie beschreibst ist, dsa ich in der DLL speicher für die Bilddaten reservieren müßte, was aber nicht geht (zumindest ist er bei mir immer abgeschmiert sobald ich das versucht habe) :( |
Wie hast du denn den Speicher allokiert? Mit einem GetMem() sollte es eigentlich keine Probleme geben, sonst würden schon ganz andere Dinge nicht funktionieren.
Aya - Mi 25.10.06 00:03
Hi,
ob ich GetMem ausprobiert hab weiß ich jetzt nicht genau... aber ich weiß, daß dashier nicht geht:
(Procedure/function einer DLL)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure loadImage(Filename: PChar; var Result: TBild) begin [..] SetLength(Result, 640, 480, 3); end;
function loadImage(Filename: PChar): TBild; begin [..] SetLength(Result, 640, 480, 3); end; |
und das war auch der grudn warum ich das mit der function schon aus meinem kopf gestrichen hatte :(
Mit SetLength jedenfalls geht es nicht (ausser ich binde diese ShareMem Unit ein, aber das will ich nicht)
Aya~
tommie-lie - Mi 25.10.06 00:15
Aya hat folgendes geschrieben: |
aber ich weiß, daß dashier nicht geht:[snip dynamic arrays |
Ja nee, iss klar, dynamische Arrays sind genauso wie Strings, Objekte die wild von abstrakten Klassen abgeleitet sind und ähnliches Getier nicht über DLL-Grenzen hinweg ohne Weiteres benutzbar. Genauso wenig wie sie vom VC++ aus benutzbar sind. Daß dein obiges Vorgehen mit einem (Delphi-?)Objekt dies leisten soll, erstaunt mich schon ein wenig, aber wenn es geht, bist du Änderungen am ABI entweder des MSVC oder des DCC hilfslos ausgeliefert. Wenn plötzlich einer von beiden anfängt seine Wort-Grenzen anders auszurichten oder andere Änderungen am internen Layout von Objekten vornimmt, funktioniert das Ganze schon nicht mehr.
Wie gesagt, die einzig sichere MEthode sind Pointer auf Strukturen, die du selbst bestimmst, nicht auf welche, die der Compiler dir zur Verfügung stellt.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!