INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.


Antwort schreiben 

LabVIEW Memory Manager



Wenn dein Problem oder deine Frage geklärt worden ist, markiere den Beitrag als "Lösung",
indem du auf den "Lösung" Button rechts unter dem entsprechenden Beitrag klickst. Vielen Dank!

18.02.2009, 11:42
Beitrag #1

abrissbirne Offline
LVF-Stammgast
***


Beiträge: 480
Registriert seit: Aug 2007

LV2009, LV2010
2007
EN

66123
Deutschland
LabVIEW Memory Manager
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
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
Anzeige
19.02.2009, 08:57
Beitrag #2

IchSelbst Offline
LVF-Guru
*****


Beiträge: 3.692
Registriert seit: Feb 2005

11, 14, 15, 17, 18
-
DE

97437
Deutschland
LabVIEW Memory Manager
' 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.

Jeder, der zur wahren Erkenntnis hindurchdringen will, muss den Berg Schwierigkeit alleine erklimmen (Helen Keller).
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
19.02.2009, 09:44
Beitrag #3

abrissbirne Offline
LVF-Stammgast
***


Beiträge: 480
Registriert seit: Aug 2007

LV2009, LV2010
2007
EN

66123
Deutschland
LabVIEW Memory Manager
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
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
19.02.2009, 09:54 (Dieser Beitrag wurde zuletzt bearbeitet: 19.02.2009 10:05 von rolfk.)
Beitrag #4

rolfk Offline
LVF-Guru
*****


Beiträge: 2.305
Registriert seit: Jun 2007

alle seit 6.0
1992
EN

2901GG
Niederlande
LabVIEW Memory Manager
' 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

Rolf Kalbermatter
Technische Universität Delft, Dienst Elektronik und Mechanik
https://blog.kalbermatter.nl
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
19.02.2009, 10:02 (Dieser Beitrag wurde zuletzt bearbeitet: 19.02.2009 10:11 von abrissbirne.)
Beitrag #5

abrissbirne Offline
LVF-Stammgast
***


Beiträge: 480
Registriert seit: Aug 2007

LV2009, LV2010
2007
EN

66123
Deutschland
LabVIEW Memory Manager
' 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.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
19.02.2009, 10:11 (Dieser Beitrag wurde zuletzt bearbeitet: 19.02.2009 10:12 von rolfk.)
Beitrag #6

rolfk Offline
LVF-Guru
*****


Beiträge: 2.305
Registriert seit: Jun 2007

alle seit 6.0
1992
EN

2901GG
Niederlande
LabVIEW Memory Manager
' 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

Rolf Kalbermatter
Technische Universität Delft, Dienst Elektronik und Mechanik
https://blog.kalbermatter.nl
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
Anzeige
19.02.2009, 12:00
Beitrag #7

abrissbirne Offline
LVF-Stammgast
***


Beiträge: 480
Registriert seit: Aug 2007

LV2009, LV2010
2007
EN

66123
Deutschland
LabVIEW Memory Manager
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
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
19.02.2009, 14:57
Beitrag #8

rolfk Offline
LVF-Guru
*****


Beiträge: 2.305
Registriert seit: Jun 2007

alle seit 6.0
1992
EN

2901GG
Niederlande
LabVIEW Memory Manager
' 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

Rolf Kalbermatter
Technische Universität Delft, Dienst Elektronik und Mechanik
https://blog.kalbermatter.nl
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
19.02.2009, 16:53
Beitrag #9

abrissbirne Offline
LVF-Stammgast
***


Beiträge: 480
Registriert seit: Aug 2007

LV2009, LV2010
2007
EN

66123
Deutschland
LabVIEW Memory Manager
' 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
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
19.02.2009, 17:16 (Dieser Beitrag wurde zuletzt bearbeitet: 19.02.2009 17:18 von rolfk.)
Beitrag #10

rolfk Offline
LVF-Guru
*****


Beiträge: 2.305
Registriert seit: Jun 2007

alle seit 6.0
1992
EN

2901GG
Niederlande
LabVIEW Memory Manager
' 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.

Rolf Kalbermatter
Technische Universität Delft, Dienst Elektronik und Mechanik
https://blog.kalbermatter.nl
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren to top
Antwort schreiben 


Gehe zu: