LabVIEWForum.de - whileschleife nur einmal durchlaufen

LabVIEWForum.de

Normale Version: whileschleife nur einmal durchlaufen
Du siehst gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
Seiten: 1 2
Aber eine FGV hat doch gegenüber einer globalen Variable den Vorteil, dass sie nur "einmal zur Zeit" aufgerufen werden kann, es kann also nicht gleichzeitig geschrieben und gelesen werden, wo u.U. Murks bei raus kommt. Oder habe ich das missverstanden?
Außerdem lassen sie sich leichter in den Datenfluss integrieren.
(05.06.2012 13:41 )Soean schrieb: [ -> ]Aber eine FGV hat doch gegenüber einer globalen Variable den Vorteil, dass sie nur "einmal zur Zeit" aufgerufen werden kann, es kann also nicht gleichzeitig geschrieben und gelesen werden, wo u.U. Murks bei raus kommt. Oder habe ich das missverstanden?
Außerdem lassen sie sich leichter in den Datenfluss integrieren.
Das hast Du nicht missverstanden. Mein bevorzugtes Anwendungsfeld für Globale Varibale sind Grundeinstellungen, die z.B bei der Initialisierung aus einer Ini-Datei gelesen werden und dann in unterschiedlichen SubVIs benötigt werden. Da tritt das Problem des gleichzeitigen Lesens und Schreibens und das der Einbindung in den Datenfluss überhaupt nicht auf. Der Vorteil ist, das man nicht in jedem dieser SubVIs die Eingänge dafür haben muß und dass man das Haupt-VI nicht mit Drahtverhau zumüllt.

Zum Austausch von Messdaten hingegen, bei denen diese Probleme eine Rolle spielen, würde ich auch keine FGVs benutzen. Dafür gibt es Queues und Melder, die in idealer Weise die Synchronisation von Erzeugung und Verbrauch gewährleisten. Bei einer FGV müßte man extra noch ein Statusbit fürs Handshaking haben, um sicherzustellen, daß ein Datenwert nicht zweimal gelesen wird. Und dieses Bit müßte man pollen, damit a) auf der Verbraucherseite erst gelesen wird, bis ein neuer Datenwert vorliegt, und b) auf der Erzeugerseite nicht ein neuer Datenwert eingeschrieben wird, bevor der alte gelesen ist. Das ist im Vergleich zu Queues unsäglich umständlich - bei Queues ist diese Funktionalität von vornherein implementiert.

Beipiel für ein FGV mit zusätzicher Funktionalität, wie ich es für sinnvoll halte:
FGV für Gundeinstellungen:
Beim ersten Aufruf werden der Werte automatisch aus einer ini-Datei gelesen.
Beim weiteren Lesen werden die Werte aus den internen Schieberegisteren genommen, es wird also nicht dauernd aus der ini-Date gelesen.
Beim Schreibzugriff werden die Wert in den Sschieberegistern geändert und gleichzeitig in die INI-File geschrieben.

Bei Verwendung von Globalen Variablen hätte man hingegen das INI-File-Gedöns mit im Haupt-VI. Darunter könnte die Übersichtlichkeit leiden.
Danke für die Zusammenfassung :-)

(05.06.2012 14:59 )Lucki schrieb: [ -> ]Zum Austausch von Messdaten hingegen, bei denen diese Probleme eine Rolle spielen, würde ich auch keine FGVs benutzen. Dafür gibt es Queues und Melder, die in idealer Weise die Synchronisation von Erzeugung und Verbrauch gewährleisten. Bei einer FGV müßte man extra noch ein Statusbit fürs Handshaking haben, um sicherzustellen, daß ein Datenwert nicht zweimal gesesen wird. Und dieses Bit müßte man pollen, damit a) auf der Verbraucherseite erst gelesen wird, bis ein neuer Datenwert vorliegt, und b) auf der Erzeugerseite nicht ein neuer Datenwert eingeschrieben wird, bevor der alte gelesen ist. Das ist im Vergleich zu Queues unsäglich umständlich - bei Queues ist diese Funktionalität von vornherein implementiert.

Wie unglaublich praktisch Queues sind habe ich erst vor Kurzem gelernt, bis dato habe ich die FGVs auch in den von dir beschriebenen Fällen genutzt. Mach ich nun anders.

Einen praktischen Anwendungsfall für FGVs sehe ich dennoch: In einem parallel zur Main-Schleife laufenden VI wird das Prozessabbild der digitalen Eingänge gelesen (klar, sofern vorhanden) und in eine FGV übergeben. Dieses wird an unterschiedlichen stellen im Programm abgefragt. Der Vorteil gegebenüber dem Queue liegt darin, dass ich immer das aktuelle Prozessabbild in der FGV habe, welches ich auch mehrmals abfragen kann. Der Vorteil gegenüber den globalen Variablen liegt in der Vermeidung von Fehlern bei gleichzeitigem Lesen/Schreiben.
Frage dazu: Fehler beim gleichzeitigen Lesen und Schreiben bezieht sich aber "nur" auf Fehler die aus mangelnder Synchronisierung resultieren? Sprich: Programm 1 liest, macht eine Berechnung, 2 Schreibt, 1 schreibt zurück - einen nicht konsistenten Wert, weil 2 ja in der Zwischenzeit geändert hat?

Die Schreib- und Leseoperationen selbst dürften ja atomar sein oder? Sprich: Ich kann nicht *Beispiel* einen Cluster mit 10 Elementen haben und durch gleichzeitiges schreiben mir eine Mischung aus zwei Clustern einfachen die es so nie gegeben hat? Ich krieg also immer genau einen der beiden Cluster (der zuletzt zum Zuge kommt)? Entsprechendes gilt natürlich auch für Schreiben und lesen.

*Anwendungsbeispiel: Man will einen Status schreiben der fürs Lesen nicht zeitkritisch (es ist akzeptabel für einen eng begrenzten Zeitraum mit einem Falschen Status zu arbeiten; man könnte da an eine Modusumschaltung denken) ist und hat mehrere Quellen die den setzen können. Mit atomarem Lesen und Schreiben kann man dafür globale Variablen nehmen, ohne... na ja.. wäre zumindest ne Fehlerquelle
Also von mir darfst Du da keine Antwort erwarten. Ich versuche so zu programmieren - und zwar ohne dass ich deswegen GVs vermeide -, dass solche Erscheinungen gar nicht erst auftreten können. Ein Interesse, also rein sportlich gesehen, hätte ich schon an solchen Fällen. Aber da müßte dann schon jemand mit einem real existierenden VI kommen, bei dem das Unerwüschte nicht nur herbeigeredet wird, sondern tatsächlich passiert.
Hab mir mal ein Minimalbeispiel gebastelt (Array mit 1E7 einträgen erzeugt, einmal alle = 1 einmal alle = 2; anschließend "gleichzeitig" in eine Lokale Variable schreiben lassen und danach vergleich mit 1 und 2 und nen Oder über das Array von Bool. Bei ner Atomaren Operation sollte nur einmal True rauskommen, bei ner Mischung sollte ich am Ende zweimal True haben.

Ergebnis: Ich sehe IMMER (reproduzierbar), dass 1 offenbar als zweites zum Zuge kommt, da das Array immer aus nur 1en besteht die also als zweites geschrieben werden. Heist: 1. Offenbar ist das atomar (habe extra noch Leitungen angefügt, um sicherzustellen, dass eine Speicherkopie erstellt werden muss. So nur ne Referenz in die (hier) lokale Variable geschrieben werden muss sollte das sowieso atomar sein, leider kann man jedoch Cluster schlecht testen (da müsste man schon wirklich Aufwand Betreiben um Kollisionen zu erzeugen....).

Weis jemand wie Labview die lokalen und globalen Variablen intern handhabt? Mir fiel grade auf, dass man atomarität relativ einfach sicherstellen kann, wenn die Global / Lokal nur eine Referenz auf eine Referenz auf das Objekt enhält. Dann kann man erst eine komplette (valide) Speicherkopie erzeugen und dann auf diese verweisen (ohne die globale Adresse des Speicherbereichs ändern zu müssen)...


P.S: Interessant finde ich an dem Minimalbeispiel, dass scheinbar ein fester Ablauf vorliegt, obwohl ich erwarten würde, dass mal das eine, mal das andere Array eher zum Zuge kommt. Ka ob ich beim "Erzeugen von Gleichzeitigkeit" da noch nen Denkfehler habe...
(08.06.2012 12:44 )Kiesch schrieb: [ -> ]P.S: Interessant finde ich an dem Minimalbeispiel, dass scheinbar ein fester Ablauf vorliegt, obwohl ich erwarten würde, dass mal das eine, mal das andere Array eher zum Zuge kommt. Ka ob ich beim "Erzeugen von Gleichzeitigkeit" da noch nen Denkfehler habe...
Dass, sobald das VI gespeichert wurde, immer dasselbe passiert, ist IMHO normal. Denn LabVIEW erzeugt im Hintergrund Maschinencode, der dann natürlich deterministisch und immer identisch abläuft. Hauptproblem bei solchen Race-Condition: Auf Grund des Source-Codes hast du keine Chance vorherzusagen, was nun intern zuerst ausgeführt wird.
Was nicht passieren kann (richtig erkannt), dass am Ende eine "Mischung" aus den beiden unterschiedlichen Arrays rauskommt.

Gruß, Jens
Das Entscheidende ist doch nicht, ob die Reihenfolge zufällig ist oder nicht, sondern dass die Reihenfolge von Labview bestimmt wird und nicht wie der Programmierer sich das denkt. Und: Dass, auch wenn die Reigenfolge hier im Beispiele deterministisch erscheint, man sich darauf nicht zu 100% verlassen kann und kein pfofessionelles Programm darauf aufbauen sollte Vielleicht ist es z.B nach der Kompilierung anders als in der Entwicklungsumgebung, oder es wird anders, nachdem etwas Nebensächliches im Programm geändert wurde.
In Deinem Fall könnte es vielleicht damit zusammenhängen, welche lokale Variable zuerst erstellt wurde. Ein Denkfehler liegt bestimmt nicht vor.
Ich glaube erkannt zu haben, daß einfache Variablen, auch lokale, (vielleicht auch Eigenschaftsknoten) immer erst gelesen/geschrieben werden, und erst dann kommen Strukturen und SubVIs dran. Aber schriftlich wird man das von NI auch nicht bestätigt bekommen.
Z.B wird ein Stop-Knopf in einer While-Schleife immer mit zuerst gelesen, und erst dann kommt das andere dran. Die Anordnung des Stop-Anschlusses und des Stop-Knopfes ganz rechts unten suggeriert aber das Gegenteil So kommt es, daß man sich als Neuling erst mal wundert, wenn nach Stop die Schleife noch einmal mehr ausgeführt wird als erwartet.
(08.06.2012 13:29 )jg schrieb: [ -> ]
(08.06.2012 12:44 )Kiesch schrieb: [ -> ]P.S: Interessant finde ich an dem Minimalbeispiel, dass scheinbar ein fester Ablauf vorliegt, obwohl ich erwarten würde, dass mal das eine, mal das andere Array eher zum Zuge kommt. Ka ob ich beim "Erzeugen von Gleichzeitigkeit" da noch nen Denkfehler habe...
Dass, sobald das VI gespeichert wurde, immer dasselbe passiert, ist IMHO normal. Denn LabVIEW erzeugt im Hintergrund Maschinencode, der dann natürlich deterministisch und immer identisch abläuft. Hauptproblem bei solchen Race-Condition: Auf Grund des Source-Codes hast du keine Chance vorherzusagen, was nun intern zuerst ausgeführt wird.
Was nicht passieren kann (richtig erkannt), dass am Ende eine "Mischung" aus den beiden unterschiedlichen Arrays rauskommt.

Gruß, Jens

Sollten nicht an der Stelle zwei Threads erzeugt werden die parrallel zueinander sind? So dass der Ablauf durch zwei parrallel laufende Prozesse eben gerade nichtmehr deteministisch ist? So hatte ich das zumindest bisher immer verstanden.

@Lucki

Es gibt genügend Anwendungen in denen Racing Conditions zwar auftreten aber die Abarbeitungsreihenfolge nicht Problematisch ist. Wenn ich mein Programm von nem Modus Datenaufnahme nach Stop umschalten soll ist es in 99 von 100 Fällen (Sprich: Anforderungen an das Program) egal ob ich einen Wert noch mitnehme (weil ich erst lese bevor ich stopp schreibe) oder sofort stoppe. etc. pp.
Falls ich doch das Pech habe den restlichen einen Fall programmieren zu müssen kann ich der Abarbeitungsreihenfolge immer noch Beachtung schenken. Es ist halt nur typischerweise nicht notwendig.
Das wichtigste ist doch nach wie vor sich darüber bewusst zu sein was man tut... Die meisten Fehler entstehen doch eher daraus, dass sich mancher garnicht darüber bewusst ist wenn er sich Racing Conditions einhandelt.
Das man wenn man eine Reihenfolge sicherstellen will die auch im Programm erzwingen muss ist ne ganz andere Frage.
Zitat:Es gibt genügend Anwendungen in denen Racing Conditions zwar auftreten aber die Abarbeitungsreihenfolge nicht Problematisch ist. Wenn ich mein Programm von nem Modus Datenaufnahme nach Stop umschalten soll ist es in 99 von 100 Fällen (Sprich: Anforderungen an das Program) egal ob ich einen Wert noch mitnehme (weil ich erst lese bevor ich stopp schreibe) oder sofort stoppe. etc. pp.
Richtig, in den meisten Fällen ist das egal, nur würde ich das dann nicht als Racing Condition bezeichenen. Auch das Beispiel mit der for-Schleife wollte ich nicht so verstanden wissen. Ich würde sagen, eine Racing Condition ist gerade dadurch definiert, dass zwei Ausführungen quasi gleichzeitig erfolgen und dass die Reihenfolge nicht egal ist.
Seiten: 1 2
Referenz-URLs