LabVIEWForum.de
LabVIEW Memory Manager - Druckversion

+- LabVIEWForum.de (https://www.labviewforum.de)
+-- Forum: LabVIEW (/Forum-LabVIEW)
+--- Forum: LabVIEW Allgemein (/Forum-LabVIEW-Allgemein)
+---- Forum: DLL & externer Code (/Forum-DLL-externer-Code)
+---- Thema: LabVIEW Memory Manager (/Thread-LabVIEW-Memory-Manager)

Seiten: 1 2


LabVIEW Memory Manager - abrissbirne - 18.02.2009 11:42

Ich beschäftige mich momentan ein wenig mit den Funktionen für externe Codes. Ich habe eine Datenaufnahme in C++ innerhalb meines LabVIEW Projektes. Dort bekomme ich ein 1dimensionales Ergebnisarray. Ich habe mir überlegt folgendes in meinem Skript einzubauen:
1. Ich reserviere mit über Handles dynamisch Speicher.
2. Ich schreibe das Datenaufnahmearray dort hinein.
3. Ich löse ein Event in meiner LV Eventstruktur aus, welches mir die aufgenommenen Daten übergibt.
4. Ich gebe den Speicher wieder frei.

Soweit ok denk ich mal. Ich habs dann so versucht:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>Zu 1.:
uInt16 **ArrayMemoryHdl;
ArrayMemoryHdl = (uInt16 **)DSNewHClr(sizeof(uInt16)*81920);

Zu 2.:
MoveBlock((void*)Datenarray, (UHandle*)ArrayMemoryHdl, 81920);

Zu 3.:
PostLVUserEvent(*Value, (UHandle*)&ArrayMemoryHdl);

Zu 4.:
DSDisposeHandle((UHandle)ArrayMemoryHdl);</div>

Leider löst mir die Zeile PostLVUserEvent ein Fehler aus das er wohl die Daten an der falschen Stelle im Speicher sucht. Leider verstehe ich nicht warum. Hat von euch jemand eine Idee?

Danke


LabVIEW Memory Manager - IchSelbst - 19.02.2009 08:57

' schrieb:Zu 1.:
uInt16 **ArrayMemoryHdl;
ArrayMemoryHdl = (uInt16 **)DSNewHClr(sizeof(uInt16)*81920);
Bist du sicher, dass da beidesmal zwei Sterne hingehören? Zwei Sterne heißt doch Pointer auf Pointer auf Daten. Für ein 1DArray reicht doch ein Pointer - im Endeffekt also ein PChars (PWideChar). DSNewHClr erzeugt auch nur einen Pointer auf Daten. Da ist mit Array-Handle nichts.

Zitat:Zu 2.:
MoveBlock((void*)Datenarray, (UHandle*)ArrayMemoryHdl, 81920);
Das wäre ja richtig (fast: muss heißen sizeof(uInt16)*81920, statt nur 81920).
Hier wird kopiert von pointer zu Pointer. Allerdings beißt sich "(UHandle*)ArrayMemoryHdl" mit der Deklaration "uInt16 **ArrayMemoryHdl;". Du überschreibst hier den Handle, nicht die Daten. Fehlt hier ein & ?

Zitat:Zu 3.:
PostLVUserEvent(*Value, (UHandle*)&ArrayMemoryHdl);
Da kann ich jetzt nix zu sagen. Aber ob das Ziel ein Array ist oder ein PChar, sollte dem Befehl egal sein.

Zitat:Zu 4.:
DSDisposeHandle((UHandle)ArrayMemoryHdl);
Das ist richtig - bei einem Stern.


LabVIEW Memory Manager - abrissbirne - 19.02.2009 09:44

Erstmal danke für deine Kommentare.
' schrieb:Bist du sicher, dass da beidesmal zwei Sterne hingehören? Zwei Sterne heißt doch Pointer auf Pointer auf Daten. Für ein 1DArray reicht doch ein Pointer - im Endeffekt also ein PChars (PWideChar). DSNewHClr erzeugt auch nur einen Pointer auf Daten. Da ist mit Array-Handle nichts.
Es wird empfolen dynamische Speicherallozierung mittels Handles vorzunehmen. Wenn ich es nun richtig verstanden habe bedeuten zwei Sterne ein Pointer auf ein Pointer bzw. eine Adresse auf eine Adresse wobei der zweite Pointer eine Adresse auf den Master Pointer beschreibt. Ich fordere mir also Speicher einer bestimmten Größe an und der Memory Manager reserviert den Speicher und fügt diese Adresse in eine Liste des Master Pointers hinzu.
Im Prinzip bin ich mir sehr sicher das diese Allozierung stimmt.

' schrieb:Das wäre ja richtig (fast: muss heißen sizeof(uInt16)*81920, statt nur 81920).
Da hast du denke ich recht, danke.

' schrieb:Hier wird kopiert von pointer zu Pointer. Allerdings beißt sich "(UHandle*)ArrayMemoryHdl" mit der Deklaration "uInt16 **ArrayMemoryHdl;". Du überschreibst hier den Handle, nicht die Daten. Fehlt hier ein & ?
Das könnte auch eine Fehlerquelle sein. In der Beschreibung von MoveBlock steht das zwei Pointer als Übergabeparameter erwartet werden. Der Erste auf die Quelladresse und der Zweite auf die Zieladresse. Könnte also sein das die Übergabe so aussehen müsste:<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>MoveBlock((void*)Datenarray, (UHandle**)&ArrayMemoryHdl, 81920);</div>

' schrieb:Da kann ich jetzt nix zu sagen. Aber ob das Ziel ein Array ist oder ein PChar, sollte dem Befehl egal sein.
Ich denke das sollte funktionieren.

' schrieb:Das ist richtig - bei einem Stern.
ArrayMemoryHdl wurde von mir als Handle deklariert, desshalb sollte auch das stimmen.

Korrigiert mich bitte wenn ich etwas falsches sage. Ich möchte ja auch immer dazulernen ;-)

THX


LabVIEW Memory Manager - rolfk - 19.02.2009 09:54

' schrieb:Ich beschäftige mich momentan ein wenig mit den Funktionen für externe Codes. Ich habe eine Datenaufnahme in C++ innerhalb meines LabVIEW Projektes. Dort bekomme ich ein 1dimensionales Ergebnisarray. Ich habe mir überlegt folgendes in meinem Skript einzubauen:
1. Ich reserviere mit über Handles dynamisch Speicher.
2. Ich schreibe das Datenaufnahmearray dort hinein.
3. Ich löse ein Event in meiner LV Eventstruktur aus, welches mir die aufgenommenen Daten übergibt.
4. Ich gebe den Speicher wieder frei.

Soweit ok denk ich mal. Ich habs dann so versucht:
Zu 1.:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>uInt16 **ArrayMemoryHdl;
ArrayMemoryHdl = (uInt16 **)DSNewHClr(sizeof(uInt16)*81920);
</div>
Ein LabVIEW memory handle für u16 sieht aber so aus:

<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
struct {
int32 num;
uInt16 elm[0];
} **UInt16Handle;
</div>
und der entsprechende Code um das anzulegen dann:

<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
UInt16Handle ArrayMemoryHdl;
ArrayMemoryHdl = (UInt16Handle)DSNewHClr(sizeof(int32) + sizeof(uInt16)*81920);
</div>

resp. noch besser:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
UInt16Handle ArrayMemoryHdl = NULL;
err = NumericArrayResize(uW, 1, (UHandle*)&ArrayMemoryHdl, 81920);
</div>

Zitat:Zu 2.:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>MoveBlock((void*)Datenarray, (UHandle*)ArrayMemoryHdl, 81920);</div>

Das wird dann entsprechend:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
MoveBlock(Datenarray, (*ArrayMemoryHdl)->elm, sizeof(uInt16)*81920);
(*ArrayMemoryHdl)->num = 81920;
</div>
Zitat:Zu 3.:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>PostLVUserEvent(*Value, &ArrayMemoryHdl);</div>

Wär ich jetzt mal nicht ganz sicher ob das denn der Pointer auf das ArrayHandle sein soll oder nur das Handle selber. Natürlich muss die entsprechende UserEvent Refnum nur dereferenziert werden wenn Du sie "by reference" an deine Funktion übergeben hast und muss diese in LabVIEW als Datenelement ein 1D Array of uInt16 haben.

Zitat:Zu 4.:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>DSDisposeHandle((UHandle)ArrayMemoryHdl);</div>

Tra ra! Das stimmt mit fast 100% Wahrscheinlichkeit nicht! Du hast das Handle mit PostLVUserData an LabVIEW übergeben und von da an managed LabVIEW das weiter. Ich habe noch nie Handles mit PostLVUserData verarbeitet aber die Art und Weise wie die Speicherverwaltung in LabVIEW funktioniert lässt mich schwer vermuten dass PostLVUserData alle variable sized Datenelemente ganz einfach erbt.

Zitat:Leider löst mir die Zeile PostLVUserEvent ein Fehler aus das er wohl die Daten an der falschen Stelle im Speicher sucht. Leider verstehe ich nicht warum. Hat von euch jemand eine Idee?

Nicht verwunderlich wenn Du LabVIEW einen Datentyp gibst der so einfach nicht stimmt.

Rolf Kalbermatter


LabVIEW Memory Manager - abrissbirne - 19.02.2009 10:02

' schrieb:Ein LabVIEW memory handle für u16 sieht aber so aus:

<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
struct {
int32 num;
uInt16 elm[0];
} **UInt16Handle;
</div>
und der entsprechende Code um das anzulegen dann:

<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
UInt16Handle ArrayMemoryHdl;
ArrayMemoryHdl = (UInt16Handle)DSNewHClr(sizeof(int32) + sizeof(uInt16)*81920);
</div>
Ja ich habe es vorher so definiert:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>typedef struct {
int32 dimSize;
uInt16 value[0];
} Array;
typedef Array **ArrayHdl;</div>
Hätte ich vll. dazuschreiben sollen.

' schrieb:Das wird dann entsprechend:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
MoveBlock(Datenarray, (*ArrayMemoryHdl)->elm, sizeof(uInt16)*81920);
(*ArrayMemoryHdl)->num = 81920;
</div>
Wär ich jetzt mal nicht ganz sicher ob das denn der Pointer auf das ArrayHandle sein soll oder nur das Handle selber. Natürlich muss die entsprechende UserEvent Refnum nur dereferenziert werden wenn Du sie "by reference" an deine Funktion übergeben hast und muss diese als Datenelement ein 1D Array of uInt16 haben.
Tra ra! Das stimmt mit fast 100% Wahrscheinlichkeit nicht! Du hast das Handle mit PostLVUserData an LabVIEW übergeben und von da an managed LabVIEW das weiter. Ich habe noch nie Handles mit PostLVUserData verarbeitet aber die Art und Weise wie die Speicherverwaltung in LabVIEW funktioniert lässt mich schwer vermuten dass PostLVUserData alle variable sized Datenelemente ganz einfach erbt.
Nicht verwunderlich wenn Du LabVIEW einen Datentyp gibst der so einfach nicht stimmt.

Rolf Kalbermatter

Vielen Dank. Scheine ja schon ein paar Fehler gemacht zu haben.
Also wenn ich dich richtig verstadnen habe brauche ich den Speicher gar nicht mehr freigeben, da sich LV nach der Übergabe darum kümmert?

Danke nochmal.


LabVIEW Memory Manager - rolfk - 19.02.2009 10:11

' schrieb:Allerdings habe ich das:
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>
uInt16 **ArrayMemoryHdl;

ArrayMemoryHdl = (uInt16 **)DSNewHClr(sizeof(uInt16)*81920);//DSNewHandle(sizeof(uInt16));
</div>
aus dem Manual "Using External Code in LabVIEW. Deshalb hab ich auch gesagt das es stimmen muss.
Kommt immer darauf an wofür. Um ein LabVIEW Array Handle anzulegen ist das ganz einfach falsch und wird in eben diesem Manual auch ganz nachdrücklich darauf gewiesen dass man besser NumericArrayResize() verwendet da das eventuelle Issues mit Alignment automatisch korrekt abhandelt.

Zitat:Also wenn ich dich richtig verstandnen habe brauche ich den Speicher gar nicht mehr freigeben, da sich LV nach der Übergabe darum kümmert?

Ich kann es Dir nicht garantieren aber es erschiene mir logisch so. Die Dokumentation zu PostLVUserEvent ist da in dieser Hinsicht schon "ziemlich" dünn.

Rolf Kalbermatter


LabVIEW Memory Manager - abrissbirne - 19.02.2009 12:00

Ich habe tatsächlich ein Event registriert, welches den Datentyp Int16 und nicht UI16 trug. Habs geändert und schon funktionierts.

' schrieb:Ich kann es Dir nicht garantieren aber es erschiene mir logisch so. Die Dokumentation zu PostLVUserEvent ist da in dieser Hinsicht schon "ziemlich" dünn.

Rolf Kalbermatter
Danach habe ich als Test (da mom keine Hardware greifbar war) mal ein paar bereits aufgenommener Daten an die DLL übergeben damit diese das Event auslöst und die Daten übergibt. Wenn ich den Speicher innerhalb meines C Codes nicht wieder freigebe läuft direkt der RAM hoch bis zum Überlauf. Mit Speicherfreigabe kann man das schön in einer Endlosschleife laufen lassen, ohne das der Speicher in irgendeiner Form ansteigt.

Danke nochmal besonders an rolfk


LabVIEW Memory Manager - rolfk - 19.02.2009 14:57

' schrieb:Ich habe tatsächlich ein Event registriert, welches den Datentyp Int16 und nicht UI16 trug. Habs geändert und schon funktionierts.
Da ist was faul dran. uInt16 oder int16 sind speichertechnisch genau dasselbe. Das sollte höchstens Einfluss auf die Sinnhaftigkeit der Zahlen haben die Du in LabVIEW siehst aber nicht ob es funktioniert, crasht oder was auch immer.
Zitat:Danach habe ich als Test (da mom keine Hardware greifbar war) mal ein paar bereits aufgenommener Daten an die DLL übergeben damit diese das Event auslöst und die Daten übergibt. Wenn ich den Speicher innerhalb meines C Codes nicht wieder freigebe läuft direkt der RAM hoch bis zum Überlauf. Mit Speicherfreigabe kann man das schön in einer Endlosschleife laufen lassen, ohne das der Speicher in irgendeiner Form ansteigt.

Hmm also werden die Daten kopiert. Nicht ganz was ich jetzt erwartet hätte, aber auf der anderen Seite steht ja in der Dokumentation dass die Daten für alle Event Strukturen welche auf das betreffende Event abonniert sind in die Event Queue geschoben werden. Da müsste für die 2te und jede weitere Event Queue eh ein Kopie gemacht werden so dass es wohl einfacher war das grundsätzlich immer zu tun.

Um effizient Daten nach LabVIEW zu transportieren ist das aber nicht ideal.

Rolf Kalbermatter


LabVIEW Memory Manager - abrissbirne - 19.02.2009 16:53

' schrieb:Da ist was faul dran. uInt16 oder int16 sind speichertechnisch genau dasselbe. Das sollte höchstens Einfluss auf die Sinnhaftigkeit der Zahlen haben die Du in LabVIEW siehst aber nicht ob es funktioniert, crasht oder was auch immer.
Hmm also werden die Daten kopiert. Nicht ganz was ich jetzt erwartet hätte, aber auf der anderen Seite steht ja in der Dokumentation dass die Daten für alle Event Strukturen welche auf das betreffende Event abonniert sind in die Event Queue geschoben werden. Da müsste für die 2te und jede weitere Event Queue eh ein Kopie gemacht werden so dass es wohl einfacher war das grundsätzlich immer zu tun.

Um effizient Daten nach LabVIEW zu transportieren ist das aber nicht ideal.

Rolf Kalbermatter
Was wäre denn Ideal? Ich dachte mir, da mein Toplevel VI nach der Producer-Consumer-Loop Architektur aufgebaut ist, dass dies wunderbar in diesen Aufbau passt. Meine Producer empfängt quasi die Daten und kann diese weiterreichen.

Allerdings wenns irgendwie besser geht, wäre ich dankbar wenn du mir verraten könntest wie?

Danke


LabVIEW Memory Manager - rolfk - 19.02.2009 17:16

' schrieb:Was wäre denn Ideal? Ich dachte mir, da mein Toplevel VI nach der Producer-Consumer-Loop Architektur aufgebaut ist, dass dies wunderbar in diesen Aufbau passt. Meine Producer empfängt quasi die Daten und kann diese weiterreichen.

Allerdings wenns irgendwie besser geht, wäre ich dankbar wenn du mir verraten könntest wie?

Danke

Tja ich habe das mal so getan dass ich eine Funktion hatte der das Handle als Parameter passed by reference übergeben wurde. Dann habe ich das Handle das in der DLL alloziert und gefüllt wurde mit dem Handle das von LabVIEW kam ganz einfach ausgetauscht. Ersparte mir eine Datenkopie. Du musst in Deiner DLL Funktion nur darauf achten dass das neue Handle entweder ein gültiges Handle ist, das man also mit DSSetHandleSize() in der Grösse anpassen kann, oder ein NULL Handle. (LabVIEW verwendet intern, und bei Handle Parametern die passed by reference sind, NULL als Alternative für ein leeres Handle also ein Array oder String der nur die Längenangabe 0 enthält.) In dem Fall müsste man dann halt DSNewHandle() verwenden.

Wenn Du aber sowieso NumericArrayResize() verwendest erübrigt sich diese letzte Bemerkung aber, da diese Funktion auch mit NULL Handles korrekt umgeht.

Rolf Kalbermatter

PS: Den Handle Exchange solltest Du mit einer Funktion wie etwa InterlockedExchange() machen da Du ansonsten in Race Conditions laufen kannst.