LabVIEWForum.de
VI mit externer DLL macht kein Multithreading - 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: VI mit externer DLL macht kein Multithreading (/Thread-VI-mit-externer-DLL-macht-kein-Multithreading)

Seiten: 1 2


VI mit externer DLL macht kein Multithreading - wernerIBN - 03.12.2009 19:05

Ich habe eine Reihe von VIs erstellt, die eine von mir VS2005 erstellte C-DLL aufrufen, in welche ich threadsicher Funktionen erstellt habe, um über winsock mit Messgeräten zu kommunizieren. Es gibt da 4 Funktionen, im Prinzip open-send-read-close. Im VI führe ich immer diese 4 Funktionen aus. Jedes Gerät hat eine Verbindungsnummer, über die ich in der DLL auf Verbindungsdetails (Port, IP-ADresse etc) über ein Array zugreife. Also können mehrere dieser Zugriffe gleichzeitig, also in C in verschieden Thread laufen, ohne sich gegenseitig zu beeinflussen.

In LabVIEW stelle ich nun fest:
Gerät 1 benötigt fürs VI 100ms
Gerät 2 benötigt fürs VI 200ms
Gerät 3 benötigt fürs VI 100ms
Gerät 4 benötigt fürs VI 300ms

wenn ich die VIs einzeln aufrufe.

Wenn ich alle 4 VIs in einen Case stelle, ohne irgendwelche Verbindungen zueinander, dauert der gesamte Case 700ms - also als ob die VIs nacheinander laufen. das verstehe ich nicht. Gehe ich richtig in der Annahme, dass 4 VIs in einem Case, die nicht irgendwie verbunden sind, parallel abgearbeitet werden sollten ?

Ich vermute mal, das LabVIEW sieht, in allen 4 VIs werden jeweils die 4 DLL-Funktionen open-send-read-close aufgerufen, und die sind natürlich in jedem einzelnen VI sauber mit dem Error-Cluster durchverkabelt, also verbunden. Aber es können gleichzeitig 4 VIs open aufrufen, aber LV machts nicht.

Darauf hin habe ich an folgenden Einstellungen gedreht, aber keine echte Erkenntniss gewonnen, was genau da passiert:

Frage 1:
VI-Eigenschaften -> Ausführung -> Ablaufinvariante Ausführung an oder aus

Was genau macht das, bringt mich das näher an meine Ziel der parallelen Ausführung ?

Frage 2:
Knoten zum Aufruf externer Bibliotheken -> In UI-Thread ausführen oder In beliebigem Thread ausführen

Ich habe den Eindruck, dass sich ausser der Farbe nichts ändert, es dauert immer 700ms.

Werner


VI mit externer DLL macht kein Multithreading - rolfk - 03.12.2009 19:48

Beispielscode, von was Du machst würde enorm helfen. Meine Kristallkugel :glas1:ist schon eine Weile defekt.


VI mit externer DLL macht kein Multithreading - IchSelbst - 03.12.2009 22:39

' schrieb:In LabVIEW stelle ich nun fest:
Gerät 1 benötigt fürs VI 100ms
Gerät 2 benötigt fürs VI 200ms
Gerät 3 benötigt fürs VI 100ms
Gerät 4 benötigt fürs VI 300ms

wenn ich die VIs einzeln aufrufe.
Ist das jetzt ein einziges VI, das du vier Mal auf das Blockdiogramm positioniert hast oder sind das tatsächlich vier unterscheidliche VIs, die jeweils einmal vorhanden sind?

Sind es vier unterschiedliche VIs, muss es so gehen, wie du willst.

Ist es ein VI, das vier Mal verwendet wird, muss das VI mindestens als ablaufinvariant deklariert werden, damit es so geht, wie du willst.

Zitat:Frage 1:
VI-Eigenschaften -> Ausführung -> Ablaufinvariante Ausführung an oder aus
Was genau macht das, bringt mich das näher an meine Ziel der parallelen Ausführung ?
Ablaufinvariante VIs sind wie Instanzen einer Klasse. Hier werden vier Stück tatsächlich parallel abgearbeitet.
Ist ein VI nicht ablaufinvariant, gibt es nur eine einzige Instanz. Hier würden vier Stück nacheinander abgearbeitet.

Zitat:Frage 2:
Knoten zum Aufruf externer Bibliotheken -> In UI-Thread ausführen oder In beliebigem Thread ausführen
Genau: Welches musst du nehmen, damit die DLL mehrfach aufgerufen respektive der DLL-Knoten abgearbeitet werden kann. Das weiß ich nicht, hab ich vergessen, hab ich erst einmal gebraucht. Aber mein Vorredner kann dir sagen, was du brauchst.


VI mit externer DLL macht kein Multithreading - rolfk - 04.12.2009 07:57

' schrieb:Genau: Welches musst du nehmen, damit die DLL mehrfach aufgerufen respektive der DLL-Knoten abgearbeitet werden kann. Das weiß ich nicht, hab ich vergessen, hab ich erst einmal gebraucht. Aber mein Vorredner kann dir sagen, was du brauchst.

:DIch denke die Namensgebung sollte da doch schon sehr deutlich sein!

Im UI Thread (beachte das Fehlen eines Plural s am Ende) ausführen bedeutet doch in dem EINEN, SPEZIELLEN Thread, und da es davon eben nur EINEN gibt kann jeweils nur EINE Sache gleichzeitig laufen. Ob das jetzt User Interface Updates sind, aufrufen von Threadunsafen OS Funktionen, oder halt Deiner DLL Funktionen macht nichts aus.

In beliebigem Thread ausführen, bedeutet dann dass die entsprechende Funktion in jedem beliebigen Thread ausgeführt werden darf. Das heisst ganz egal in welchen Thread LabVIEW in dem Moment im VI ist, die Funktion darf ohne Umschweife aufgerufen werden. Und da LabVIEW per Execution System mit Thread Pools arbeitet, bedeutet das halt das innerhalb eines VIs mehrer Code Teile in verschiedenen Threads sein können (je nach LabVIEW Version und Anzahl CPU Cores glaube ich bis zu 16 derzeitig.

Das heisst wenn Du die Call Library Nodes alle in ein VI setzt (mich verwirrt aber der Ausdruck dass die da in einen Case kommen darum meine Frage um ein Beispiel) muss dieses VI ablaufinvariant sein UND alle Call Library Nodes müssen gleichzeitig auf "in beliebigem Thread ausführen" eingestellt sein. Sowohl "nicht ablaufinvarientes VI" als auch "im UI auszuführende Call Library Nodes" serialisieren unabhängig voneinander jede für sich den Aufruf in die DLL.

Nun noch ein Tipp im Zusammenhang mit der erwähnten Case Struktur. Wenn das jetzt so ist wie ich es mir denke, hast Du da ein VI mit einer Case Struktur und in jedem Case eine bestimmte Call Library Node um eine Funktion aufzurufen. Warum? Mach doch einfach ein VI pro Call Library Node. Das ist viel logischer in der Benützung und macht die Einstellung der Ablaufvarianz eines VIs schon mal etwas weniger kritisch. Denn typisch will man Operationen wie Open und Close gar nicht mal ablaufinvarient ausführen. Das bringt nähmlich in den meisten Fällen rein gar nichts ausser einer Chance um unangenehme Race Conditionen zu provozieren. Wo man hingegen bei der Kommunikation mit mehreren Geräten viel gewinnen kann, ist wenn entsprechende Read und Write Operationen ablaufinvarient ausgeführt werden können.


VI mit externer DLL macht kein Multithreading - wernerIBN - 04.12.2009 11:23

Also erst mal vielen Dank für die hilfreichen und sehr sachkundigen Antworten.
Ich kann momentan keinen sinnvollen Beispielcode senden, da mein Projekt von 3 Leuten bearbeitet wird, und ich erst mal ein Reduziertes Projekt machen muss, damit man das Problem isoliert erkennt, mach ich aber sobald ich etwas Luft habe.

Ich denke aber, ich kann euch (rolfk und IchSelbst) genau erklären wo mein Problem liegt, Ihr seid ganz nah dran.

Erst mal zu euren Antworten, und meiner Zusammenfassung dazu:

1.) Ablaufinvariante Ausführung an oder aus
Ablaufinvariant an: mehrere gleiche VIs werden parallel abgearbeitet.
Ablaufinvariant aus: mehrere gleiche VIs werden nacheinander abgearbeitet.

2.) In UI-Thread ausführen oder In beliebigem Thread ausführen
In UI-Thread ausführen: Im UI Thread ausführen bedeutet in dem EINEN, SPEZIELLEN Thread, und da es davon eben nur EINEN gibt kann jeweils nur EINE Sache gleichzeitig laufen.
In beliebigem Thread ausführen: läuft gleichzeitig und mehrfach.

So hab ichs auch gedacht, aber es bisher nicht so hinbekommen, dass meine 4 VIs gleichzeitig laufen.


Ich erklärs jetzt haarklein, damits klar wird:

Ich habe eine DLL, werner.dll.
In werner.DLL sind 4 Funktionen: open-send-read-close
open öffnet eine TCP/IP-Verbindung zu einer bestimmten IP-Adresse mit einem bestimmten Port und merkt sich das dann mit einer Verbindungsnummer.
send-read-close bekommt jeweils die Verbindungsnummer, und weiss dann auf welche Verbindung sich der Vorgang bezieht.
Soweit die DLL.

Nun habe ich 4 VIs: open.vi send.vi read.vi close.vi die jeweils per Call Library Nodes die 4 DLL-Funktionen open-send-read-close kapseln.

Ich habe nun 4 Geräte: Gerät1-Gerät2-Gerät3-Gerät4.

Die 4 Geräte haben jeweils ein eigenes VI: Gerät1.vi Gerät2.vi Gerät3.vi Gerät4.vi

In jedem der Geräte-VIs wird der Zyklus open-send-read-close durchlaufen. Natürlich könnte man sagen, warum jedes mal auf und zu machen, wäre nicht besser zu Programmbeginn einmal die Verbindung zu öffnen, und nach Ende einmal zu schliessen ? Der Grund ist, dass es Langzeitmessungen sind, und daher auch mal ein Gerät ausfallen könnte, und dann ist es kompliziert, die ausgefallenen Geräte im laufenden Betrieb wieder einzufangen. Ausserdem arbeite ich mit Queues zur Automatisierung.

Aufbau der Geräte-VIs:

Gerät1.vi besteht aus open.vi send.vi read.vi close.vi mit der Verbindungsnummer 0 und einer eigenen IP und Portadresse.
Gerät2.vi besteht aus open.vi send.vi read.vi close.vi mit der Verbindungsnummer 1 und einer eigenen IP und Portadresse.
Gerät3.vi besteht aus open.vi send.vi read.vi close.vi mit der Verbindungsnummer 2 und einer eigenen IP und Portadresse.
Gerät4.vi besteht aus open.vi send.vi read.vi close.vi mit der Verbindungsnummer 3 und einer eigenen IP und Portadresse.

open-send-read-close jedes Geräte-VIs sind auch mit einem Error-Cluster durchverkabelt.


Wenn ich nun die 4 Geräte-VIs in eine Case setze, ohne die 4 Geräte-VIs mit Wires zu verbinden, dann wird jedes Geräte-VI nur einmal aufgerufen, aber als SUB-VI wird natürlich open-send-read-close je 4 mal aufgerufen.

Ich möchte, dass die 4 Geräte-VIs parallel laufen.

Nach meiner heutigen Sicht würde ich daher wie folgt vorgehen:

1.: die Geräte-VIs Gerät1.vi Gerät2.vi Gerät3.vi Gerät4.vi bekommen Ablaufinvariant aus weil mehrere gleiche VIs nacheinander abgearbeitet werden sollen, denn es soll ja Gerät1.vi nur einmal laufen. Da kein Call Library Node in diesen Geräte-VIs ist (sondern nur in den SUB-VIs) kann ich da was UI-Thread oder beliebigem Thread angeht nix einstellen.

2.: die 4 SUB-VIs: open.vi send.vi read.vi close.vi bekommen bekommen In beliebigem Thread ausführen damit sie gleichzeitig laufen, undAblaufinvariant im Call Library Node an weil mehrere gleiche VIs gleichzeitig (aber mit verschiedenen Verbindungsnummern) abgearbeitet werden sollen, denn es sollen ja die 4 Geräte-VIs Gerät1.vi bis Gerät4.vi gleichzeitig laufen.

Sorry für die viele Schreiberei - aber es war auch für mich sehr hilfreich das aufzuschreiben, das kommt in meine Doku rein.

Sehe ich alles richtig ?

Werner


VI mit externer DLL macht kein Multithreading - IchSelbst - 04.12.2009 12:13

' schrieb:1.) Ablaufinvariante Ausführung an oder aus
Ablaufinvariant an: mehrere gleiche VIs werden parallel abgearbeitet.
Ablaufinvariant aus: mehrere gleiche VIs werden nacheinander abgearbeitet.
Hinweis:
In diesem Falle ist der Unterschied, der zwischen "das gleiche" und "das selbe" besteht, ausschlaggebend. Du meinst hier "das selbe VI". Siehe die Sendung mit der Maus, Kapitel Hose.

Zitat:Ich erklärs jetzt haarklein, damits klar wird:
Alles klar.

Zitat:1.: die Geräte-VIs Gerät1.vi Gerät2.vi Gerät3.vi Gerät4.vi bekommen Ablaufinvariant aus weil mehrere gleiche VIs nacheinander abgearbeitet werden sollen, denn es soll ja Gerät1.vi nur einmal laufen. Da kein Call Library Node in diesen Geräte-VIs ist (sondern nur in den SUB-VIs) kann ich da was UI-Thread oder beliebigem Thread angeht nix einstellen.
Ich kann deiner Logik nicht ganz folgen.
Ich würde ja folgendes sagen und zwar nur alleine bezogen auf die VIs GerätX.VI: Die Geräte-VIs Gerät1.vi Gerät2.vi Gerät3.vi Gerät4.vi bekommen Ablaufinvariant EIN.
Hinweis:
Auch wenn nur ein einziges selbes VI läuft, kann man ablaufinvariant einstellen. Nur weil es nur einmal läuft, heißt das noch lange nicht, dass ablaufinvariant aus sein muss. VIs haben keinen Parameter "UI-Thread oder beliebigem Thread". (Falls ich hier falsch liege und die doch einen haben, dann "beliebigen Thread" aktivieren.)

Zitat:2.: die 4 SUB-VIs: open.vi send.vi read.vi close.vi bekommen bekommen In beliebigem Thread ausführen damit sie gleichzeitig laufen, undAblaufinvariant im Call Library Node an weil mehrere gleiche VIs gleichzeitig (aber mit verschiedenen Verbindungsnummern) abgearbeitet werden sollen, denn es sollen ja die 4 Geräte-VIs Gerät1.vi bis Gerät4.vi gleichzeitig laufen.
Ich kann dir hier zwar folgen. Aber: verwechselst du hier nicht was? Und hier steht wieder viel zu viel.
Ich würde sagen: die 4 SUB-VIs: open.vi send.vi read.vi close.vi bekommen Ablaufinvariant EIN. Zum Parameter "UI-Thread oder beliebigem Thread" siehe oben. Die DLL-Knoten, die sich in diesen SubVIs befinden bekommen alle den Parameter "In beliebigem Thread".


VI mit externer DLL macht kein Multithreading - wernerIBN - 04.12.2009 14:05

Hallo IchSelbst,
danke für die Hinweise.


Ja, ich meine das selbe VI.

>Ich kann deiner Logik nicht ganz folgen.

Sowas hör ich öfter...

>Ich würde ja folgendes sagen und zwar nur alleine bezogen auf die VIs GerätX.VI: Die Geräte-VIs Gerät1.vi Gerät2.vi Gerät3.vi Gerät4.vi bekommen Ablaufinvariant EIN. Hinweis: Auch wenn nur ein einziges selbes VI läuft, kann man ablaufinvariant einstellen. Nur weil es nur einmal läuft, heißt das noch lange nicht, dass ablaufinvariant aus sein muss.

Das sehe ich anders, bitte aber um Klarstellung falls ich falsch liege:
Die Geräte-VIs Gerät1.vi Gerät2.vi Gerät3.vi Gerät4.vi bekommen Ablaufinvariant AUS, weil ich explizit vermeiden möchte, dass selbe VIs (Werner hat gelernt: selbes) versehentlich gleichzeitig laufen. Gerät1.vi Gerät2.vi Gerät3.vi Gerät4.vi darf gleichzeitig laufen, aber eben nicht zwei mal Gerät1.vi

>VIs haben keinen Parameter "UI-Thread oder beliebigem Thread".
Ja, so ists, die haben keinen solchen Parameter, nur das Call Library Node hat sowas.


>Ich würde sagen: die 4 SUB-VIs: open.vi send.vi read.vi close.vi bekommen Ablaufinvariant EIN. Zum Parameter "UI-Thread oder beliebigem Thread" siehe oben. Die DLL-Knoten, die sich in diesen SubVIs befinden bekommen alle den Parameter "In beliebigem Thread".

Dem stimme ich voll zu.

Da es bei mir genau so ist, aber dennoch die Ablaufzeiten von Gerät1.vi Gerät2.vi Gerät3.vi Gerät4.vi sich addieren wenn die vier in einem einzigen case befinden, statt dass der case nur solange dauert wie das längste VI, z.B. Gerät3.vi gehe ich davon aus, dass ich irgendwo noch was übersehen habe, oder noch ein anderes VI im Spiel ist, dass eben nicht "Ablaufinvariant EIN" hat.

Jetzt wo ichs schreibe, fällt mir ein, ich ahne was: mein Call Library Node hat am Path-Eingang ein VI, welches den DLL-Pfad besorgt. Das muss ich daraufhin prüfen...

Danke Werner


VI mit externer DLL macht kein Multithreading - IchSelbst - 04.12.2009 14:24

Mach dich mal vertraut mit dem Zitieren. Einfach "Zitieren" anklicken und ganz am Ende des Themas auf Antworten. Im Text dann [ quote ] und [/ quote ] einfügen.

' schrieb:Das sehe ich anders, bitte aber um Klarstellung falls ich falsch liege:
Eine explizite Vermeidung machen zu wollen ist immer sehr gut.
Noch besser allerdings ist es, versehentlich programmierte Teile noch während der Entwicklungszeit zu entfernen. Ein VI kann man nur ganz schwierig versehentlich auf das BD setzen. Und bei Aufruf über VI-Server gibt es auch Möglichkeiten. Also: Um das Versehentliche zu vermeiden lieber was anderes nehmen als ablaufinvariant.

Zitat:Jetzt wo ichs schreibe, ...
So macht man das: Rede und Gegenrede - auch wenn manchmal gilt "das hör' ich öfter". Hehe


VI mit externer DLL macht kein Multithreading - RoLe - 04.12.2009 15:30

Zitat:>VIs haben keinen Parameter "UI-Thread oder beliebigem Thread".
Ja, so ists, die haben keinen solchen Parameter, nur das Call Library Node hat sowas.
Also es gibt noch das da, siehe Bild

... aber zuerst sich in die Thematik einlesen, es ist etwas kompliziert....

... und wer es begriffen hat, kann dann noch das VI: "C:Program FilesNational InstrumentsLabVIEW 8.2vi.libUtilitysysinfo.llbThread Configuration.vi" starten und ausführen.....
... aber zuerst sich mit der Hilfe und Doku auf NI.com schlau machen, hier wird es nun schon extrem kompliziert.

Ich habe dich/euch gewarnt, Verwendung auf eigene Gefahr.Ph34r

ob das jetzt für dein Problem relevant ist, kann ich nicht sagen.


VI mit externer DLL macht kein Multithreading - rolfk - 06.12.2009 11:18

' schrieb:>VIs haben keinen Parameter "UI-Thread oder beliebigem Thread".
Ja, so ists, die haben keinen solchen Parameter, nur das Call Library Node hat sowas.

Role hat es ja schon gezeigt. Diese Einstellung gibt es eben doch! Big Grin

Zur Kommunikation mit Netzwerkdevices. Wiederholtes Open-Read-Write-Close für solche Geräte ist keine gute Idee wenn die Schnellheit wichtig ist. Das Öffnen eines Kommunikationskanals an sich kostet typischerweise schnell mal 50 bis 100 ms (Bei Verwendung von IPv6 sockets in Windows XP zumindest, gar das Doppelte). Zudem gibt es bei TCP Write noch den interessanten Nagle Algorithmus. Der verursacht bei kleinen Writepacketen ein Standarddelay von 200ms bevor das Packet den Computer echt verlässt. Den kann man mit der TCPNoDelay Socketoption zwar ausschalten, aber ohne Sicht auf die VS2005 Sourcen ist es unmöglich zu sagen ob Du da Rechnung damit getragen hast. Auch arbeitet Winsock standardmässig in blocked mode und das in C oder dergleichen anders zu machen ist nicht trivial. Je nach dem ob Du also diese Sockets verwendest oder aber eine höhere Kommunikationslibrary, kann das auch noch ein Stolperstein sein.


Ich bin also nicht ganz überzeugt dass das angedeutete Problem durch die verkehrte (oder Nicht-)Verwendung von Ablaufinvarianz verursacht wird, obwohl das natürlich auch noch sein kann. Ich weiss aber ganz sicher und habe das auch schon öfters verwendet, dass LabVIEW auch bei den Netzwerkfunktionen selber ablaufinvarient funktioniert. Das Problem der unerwarteten Laufzeitverzögerung kann also ganz einfach auch inherent an Deiner Implementation in der DLL liegen.