(09.10.2024 14:48 )Minako schrieb: Huhu,
jetzt kann ich mich nach lagne Zeit endlich mal drauf melden.
Habe mich jetzt eine Weile damit beschäftigen können und kann das VI auf jedenfall zwei mal starten.
Bin mir aber nicht ganz sicher, ob ihr das so gemeint hattet.
Es ist die einzige Variante, die ich ans laufen bekommen habe.
Es bleibt aber das Problem des Schliessens.
Im Sub VI habe ich einen Stop Button. Dieser soll die Messung abbrechen, wenn man was falsch eingegeben hat oder die Messung pausiert werden muss.
Da werde ich noch mal schauen müssen.
Ich habe noch keine Ahnung, wie man so einen Clone schließt, damit er keine Kapazitäten mehr verbraucht.
Und wie kann ich (falls ich das brauche) hergehen und einen Stop-Button des Sub.VIs im Main.VI auslesen, damit das Main.VI das Sub.VI schließen kann.
Also im Invoke Node kann ich Werte rausholen das ist kein Problem.
Nur muss das alles dem richtigen Clone zugewiesen werden.
Aktuell sage ich ja, dass er nicht aufs VI warten soll und die Whileschleife geht weiter.
Da kann ich auf kein Stop-Signal warten.
Vielen Dank für eure hilfreichen Tipps.
Hi,
da es lang wird: Kuck mal in die Beispiele "Simple Queue" und "Asynchronous Call and Collect (Using Option 0x40)" im Example Finder in Labview. Dann wird vielleicht klarer wie du das nutzen kannst.
die Variante hatte ich noch nicht gesehen. Soweit ich das sehe müsste das aber wahrscheinlich prinzipiell auch funktionieren, hat aber in dem was du konkret gebaut hast Fehler. Ich hatte das immer über "Start Asynchronous Call" auf der Application Control Palette gemacht. Das was du machst dürfte soweit ich das beurteilen kann nicht so einfach funktionieren, aus zwei Gründen:
1. Du willst zwei Messungen aufrufen, nutzt aber das gleiche File um die Daten zu dumpen - das führt im Zweifel zu nem Zugriffskonflikt, oder zumindest dazu, dass dort wirr durcheinander von beiden Messroutinen reingeschrieben wird. Besser wäre es üblicherweise das Messfile erst in der Schleife zu generieren in der du deine VIs startest um die Daten dann getrennt nach Messung wegzuschreiben (z.B. mit _1, _2 usw.).
2. Du öffnest zwar automatisch das VI und belegst die Controls mit irgendwelchen Inputs, aber du startest soweit erkennbar nur einmal das VI (die Run VI Methode). Dementsprechend sollte der dann auch nur einmal mit den entsprechend letzten Werten starten. Die "Run VI"- Methode müsste meines Erachtensin die Schleife und das "Wait Until Done" wie du es gemacht hast auf False - dann werden auch tatsächlich beide Instanzen "gleichzeitig" gestartet.
Ob die Methode den "Reentrant" Start (also mehrere parallele Instanzen des gleichen VIs die unterschiedliche Dinge machen) unterstützt weis ich garnicht, spricht aber glaube nichts dagegen (ausprobieren, dürfte an der Konfiguration des SubVIs liegen, das bei der Execution auf Reentrant eingestellt sein muss; ansonsten führt das dazu, dass die unter der Haube nacheinander abgearbeitet werden, selbst wenn deine "Run VI" Methode nicht darauf wartet, dass die zum Ende gekommen sind). Schau dazu mal in das Beispiel "Asynchronous Call and Collect (Using Option 0x40)". Der Collect (also das Wait on Asynchronous call) ist optional, in dem Beispiel zählt das quasi nur die Schleife hoch um festzustellen wann alle VIs zum Ende gekommen sind. Die Option 0x40 ist wichtig, damit die VIs parallel ausführen (das war ja meines Wissens nach deine Absicht).
Mal so bisschen Basiswissen noch dazu: Die reentrante Ausführung heist eigentlich erstmal nur, dass mehrere "Kopien" des VIs gleichzeitig laufen dürfen ohne sich gegenseitig zu stören. Der Standardfall ist halt, dass das nicht geht (was man zum Beispiel für FGVs nutzt). Also sprich, ist das VI auf "Non Reentrant Execution" eingestellt, weist du dass du bei jeder Ausführung egal wo in deinem Programm immer auf der gleichen Instanz des VIs landest (das programmierte VI selbst ist sowas wie ein "Prototyp" der angibt wie Daten verarbeitet werden, die Instanz ist eine konkrete Ausprägung dieses Prototyps, mit Daten belegt). Das führt zum einen dazu, dass bei mehreren Prozessen aus deinem Program die auf das gleiche VI zugreifen wollen (Non Reentrant) eine serielle Abarbeitung erfolgt (wer zuerst kommt darf zuerst ausführen, alle anderen müssen warten. Es gibt Anwendungsfälle wo das nützlich ist (z.B. wenn du auf Hardware schreiben willst. So lange du das gleiche VI "Non Reentrant" dazu nutzt, wird dadurch automatisch gewährleistet, dass nicht zwei Prozesse gleichzeitig versuchen die zu benutzen). Auch kannst du dadurch an einer zentralen Stelle im Program Konfigurationen ändern die dann im ganzen Program gelten (Stichwort dazu ist glaube ich Singleton).
Das Gegenteil ist halt die "Reentrant Execution" (zwei Spielarten einstellbar) - hierbei darf das SubVI mehrfach parallel ausgeführt werden. Ich meine dafür müsste es im Prinzip auch schon reichen, das SubVI in eine Schleife zu packen und keine Ausgänge abzufragen (damit der einzelne Schleifendurchlauf nicht auf den Datenfluss des SubVIs wartet). Alternativ halt den asynchronen call - der startet das VI und wartet dann ebenfalls nicht auf das beenden. Das "Problem" dabei ist, dass du für jeden Aufruf üblicherweise eine neue Kopie deines SubVis (also eine neue Instanz) startest. Die Räumen sich beim beenden der Instanz dann zwar auch wieder auf, aber es kann prinzipiell ja auch vorkommen, das du einfach dein HauptVI beenden willst und die SubVIs sich dann mit schließen sollen. Dafür musst du dann arbeiten, weil du dann irgendeine Art von Signal ans SubVI senden musst, damit es sich vorzeitig beendet. Machst du das nicht laufen die halt bis zu ihrem natürlichen Ende weiter. Beendest du dann bleiben die "blockiert" (für Bearbeitung) bzw. halt am laufen. An die Instanzen kommst du dann auch garnicht ohne weiteres ran. Da musst du also sauber arbeiten.
Variante 1: Du startest die SubVIs mit aufpoppendem Frontpanel. Mit jedem Start einer Instanz poppt dann das Frontpanal auf und du kannst gezielt in den Instanzen einzelne Abschießen bzw. alle einzeln nacheinander per Hand. Am besten noch vor dem Programmende im Blockdiagram einen Baustein einbauen der das Frontpanel wieder zumacht (dann musst du es nicht manuell schließen). Vorteil: Einfach umzusetzen. Nachteil: Viel Arbeit für den Nutzer wenn er vorzeitig beenden will. Macht mal jemand versehentlich ein FP zu läuft das außerdem trotzdem im Hintergrund weiter bis es regulär endet. Auch blöd.
Variante 2: Da kommen wir zu Queues. Auf der Palette Data Communication --> Queue operations findest du die Queue funktionen. Dazu findest du im Example finder die "Simple Queue" - da wird einfach gezeigt wie du dir eine Queue holst (obtain) und dann Daten reinschreibst und die anschließend wieder aufräumst. Wichtig zum Verständnis ist dabei nur: Die Queue hat keine "Enden" sprich: Das ist im Prinzip nur ein Speicherbereich in den beide Programmteile Daten reinlegen können - und zwar geordnet. Heist: Was zuerst reingeht, geht auch wieder zuerst raus. Willst du "Senden" und "Empfangen" als zwei Wege Kommunikation lösen (also vom HauptVI ins SubVI und umgekehrt) lässt sich das wahrscheinlich am einfachsten mit zwei Queues lösen. Eine Sendet aus dem Hauptprogram ins SubVI (so dass das HaupVI nur auf diese Queue schreibt und das SubVI nur liest = Elemente entnimmt), eine empfängt im Hauptprogram und sendet im SubVI - da du für ein Hauptprogram mehrere SubVI hast macht es strukturell am meisten Sinn eine gemeinsame Empfangsqueue zu haben auf die alle SubVI schreiben. Grund dafür ist, dass auf eine leere Queue gewartet wird. Heist: Wenn keine Daten anstehen kannst du den Teil deines Programs einfach pausieren. Meldet sich eines der SubVI indem es Daten schreibt, wird dein Hauptprogram sofort aktiv, holt sich die und verarbeitet die. Im SubVI hingegen kommen Daten nur aus dem HauptVI an, ergo es macht Sinn wenn jedes seine eigene "eingehende Queue" hat, damit du die SubVIs über die Auswahl der richtigen Queue gezielt genau dieses SubVI ansprechen kannst (zum Beispiel weil du in Messprogramm "5" den Speicherpfad der Datei verändern willst). Im SubVI machst du dann einfach nur ein Dequeue element und das wartet bis das HauptVI sich meldet (ergo das muss in einer parallelen Schleife zum Messprogram sitzen, damit es dieses nicht blockiert). Kommt da irgendwas an musst du nur noch dafür sorgen, dass das SubVI sich zum Beispiel beendet. Ich greife dafür häufig einfach mit der Value (Signaling) Eigenschaft auf den Stop Button zu (wichtig: dadurch kannst du kein Latch mehr nutzen, die Funktion musst du dann manuell im Code wiederherstellen, damit nicht bei der nächsten Ausführung Stop beim start schon "gedrückt" ist und das Program direkt wieder beendet).
Die Brachialmethode ohne viel Kommunikation wenn es dir nur um Beenden der SubVI geht:
Du erstellst nur eine Queue, übergibst die allen SubVIs und lässt die auf ein Dequeue warten. Sobald du Beenden im HauptVI bedienst, gehst du mit der Referenz auf die Queue in ein Release Queue und setzt dort den Eingang "Force Destroy?" auf True. Dann wird die Referenz sofort freigegeben, in allen SubVI läuft ein Fehler auf an dem "Dequeue Element" den du dann nur noch als Stop Signal verarbeiten musst (Fehler im Code abfangen und zurücksetzen, sonst crasht das einfach nur die SubVIs unkontrolliert!) Wenn du das eh so machst, dann kannst du aber auch gleich auf sowas wie Notifier oder noch besser Occurences zurückgreifen (Data Communication --> Synchronisation --> Notifier / Occurence). Die simpler gestrickt und nicht zum Datenaustausch gedacht und da sendest du dann auch einfach nur aus dem HauptVI ein Signal, dass die SubVIs dann als "bitte Beenden" interpretieren sollen.
Gruß Kiesch
P.S: Das war glaube ich sehr viel und ich weis auch nicht ob ichs besser erklärt habe. Kuck mal unbedingt in die Beispiele, eventuell löst das schon deine Verständnisprobleme mit Queues und Reentranter Ausführung. Gerade das Queue Beispiel ist tatsächlich sehr einfach gehalten. Da musst du dann nur parallele Schleifen auf ein HauptVI und ein SubVI abstrahieren um das für deine Zwecke nutzbar zu machen.