Tasking Library - Druckversion +- LabVIEWForum.de (https://www.labviewforum.de) +-- Forum: LabVIEW (/Forum-LabVIEW) +--- Forum: LabVIEW Code Beispiele (/Forum-LabVIEW-Code-Beispiele) +--- Thema: Tasking Library (/Thread-Tasking-Library) |
Tasking Library - macmarvin - 17.03.2009 23:22 ' schrieb:Also ich wüsste nicht, wie man mit FGVs Race Conditions bei parallelen Schleifen vermeiden könnte. Hat jemand ein Beispiel parat? Parat nicht, aber schnell gebastelt. [attachment=17297] (lv85Mac) Tasking Library - eg - 17.03.2009 23:43 Also, ich habe im Beispiel nichts besonderes gefunden, es ist ganz normale Anwendung von FGV in paralellen Schleifen. Sobald du die Wartezeit in der unteren While-Schleife auf z.B. 200 einstellst, werden einige Zahlen doppelt bzw. mehrmals angezeigt. D.h. sobald man in der unteren While-Schleife etwas ausrechnen will (z.B. integrieren), wird das Resultat nicht mehr stimmen, weil wie gesagt einige Zahlen mehrmals berechnet werden. Und ja, was hat das Wort "atomar" hier zu bedeuten? Gruß, eg Tasking Library - eg - 18.03.2009 00:00 Ne, ok. Ich habe doch was interesantes gesehen. Die Addition wurde in die FGV verlegt. In der unteren While-Schleife wird nur das Ergebnis angezeigt. Das beantwortet zumindest meine letzte Frage. Tasking Library - macmarvin - 18.03.2009 00:17 Ops... war doch noch ein kleiner Dreher bei der get/set version drin. In dieser Version sollte der Unterschied schneller in Erscheinung treten. Mit "atomar" meinte ich hier die Unteilbarkeitsforderung für die "Get->Calculate->Set"-Abfolge (auch "kritischer Abschnitt"), um keine Race Condition zu bekommen. [attachment=17300] Tasking Library - rolfk - 18.03.2009 08:12 ' schrieb:Ne, ok. Ich habe doch was interesantes gesehen. Die Addition wurde in die FGV verlegt. In der unteren While-Schleife wird nur das Ergebnis angezeigt. Das beantwortet zumindest meine letzte Frage. Also dass das Ding zwei- oder mehrmals dargestellt wird ist dann vielleicht nicht ganz optimal aber sicher keine Racecondition. Der Wert im FGV bleibt ganz einfach konsistent ganz egal was Du in 100ten von Aufrufern mit dieser FGV machst. Natürlich kannst Du wieder ein "get value", externe subtraction, und dann "set value" machen, weil Du die Mühe um eine "subtract" Methode in die FGV einzubauen zu lästig findest und hast eine neue Race Condition gemacht aber es geht hier ja nicht darum, dass man mit einer FGV keine Race Condition machen kann, sondern dass man diese so verwenden kann, dass keine Race-Condition auftreten kann. Wenn Du auch noch Synchronisation der Display Loop mit dem Update der FGV haben willst, wirst Du nicht umhin kommen eine solche auch noch einzubauen. In der Vergangenheit tat ich das so, dass ich in der FGV eine Occurrence hatte. Die wurde bei allen Modifikationen des internen Zustands gesetzt und als extra Parameter auch rausgegeben. Die Poll Loop kann dann ein Wait on Occurrence verwenden um auf solche Änderungen zu warten und geht dann zurück um diesen veränderten Wert zu lesen. Wenn Du das alles noch programmierfreundlich verpacken willst kannst Du diesen Teil noch in ein extra VI packen und wenn Du dieses VI dann noch reentrant machst kannst Du es sogar mehrmals in Deiner Applikation parallel aufrufen und jede Instanz wartet parallel. Super kräftig! Hier meine modifizierte Version. Nur schnell in 5 Minuten hineingemacht, müsst also über die optischen Unzulänglichkeiten hinwegsehen. Notiz am Rande: diese Programmierung funktioniert so schon seit LabVIEW 2 und ich verwende sie mindestens seit 1996 oder ungefähr LabVIEW 4. [attachment=17304] Rolf Kalbermatter Tasking Library - eg - 18.03.2009 11:49 Ok, ich muss nun zugeben, dass man auch mit FGVs größere Programme ohne Race Conditions erstellen kann. Man muss nur anders denken und vorgehen, als "normal". Ich erzähle mal kurz wie die Tasking Library entstanden ist. Je mehr Erfahrung ich beim Programmieren gesammelt habe, umso größer war meine Begeisterung, was die Sync Palette (+User Events) so alles kann. Nun habe ich fast alle Sync Tools in meinen Programmen benutzt und fast immer auf die selbe Weise. Der Nachrichtentyp war immer Binary-String, damit ich unterschiedliche Daten (ganz wichtig!) zwischen den Tasks austauschen kann. Jede Nachricht bestand aus einem Header + Nutzdaten. Kleines Beispiel (für i2dx) ich will eine Zahl übertragen und ein Stop, hier muss man entweder eine Queue (bzw. Notifier oder User Event) und ein Occurence nehmen. Dabei wird Occurence einen Timeout von 0 haben, ansonsten bleibt die Task kurz hängen, was ich gar nicht will. Es ist hier also besser einen undefinierten Datentyp zu nehmen. Zwar geht dann die Typanbindung verloren, aber man kann es mit dem Typedef leicht lösen. Der Typ Binary-String (und nicht Variant) ist nicht umsonst da. Erstens ist es mit VISA und TCP/IP und externen DLLs kompatibel und zweitens kann man ganz einfach mit dem Rest Of Binary String beim Unflatten auf den Rest der Daten dynamisch zugreifen. Beim Typ Variant sollte man einen Cluster aus dem Header + weiterer Variant (evtl. sogar mehrmals verschachtelt) machen und entclustern. Ich finde also das Unflatten mit dem Rest viel bequemer. Weiter geht's. Um es übersichtlich zu halten, habe ich einen Cluster aus Queue (Notifier/User Event)-Arrays gemacht. Man kann auf die einzelne Referenzen zum Abschicken oder Empfangen von Nachrichten einfach mit dem Enum-Typedef zugreifen. Später, als LVOOP kam, habe ich diesen Cluster durch eine Klasse ersetzt. Mein Ziel ist - eventgesteuertes Programmieren. D.h. ohne Timeouts, Wartezeiten und insbesondere Race Conditions zu programmieren. Es gibt also Datenquellen und Datensenken. Solange alle Datenquellen schweigen, soll im Programm nichts passieren, wirklich gar nichts. Das Programm bewegt sich nicht und frisst 0% CPU. Sobald aber z.B. ein Paket (hier vermisse ich übrigens einen unendlichen Timeout beim VISA Read) über serielle ankommt, wird es direkt (! ohne Verzögerung) verarbeitet und an die Datensenken weitergegeben. Und bis jetzt funktioniert es mit dieser Library. Noch was zum Verständnis - diese Library ist nichts anderes als ein Warpper für die Sync Palette. Tasking Library - rolfk - 18.03.2009 14:15 ' schrieb:Sobald aber z.B. ein Paket (hier vermisse ich übrigens einen unendlichen Timeout beim VISA Read) über serielle ankommt, wird es direkt (! ohne Verzögerung) verarbeitet und an die Datensenken weitergegeben. Und bis jetzt funktioniert es mit dieser Library. Hast Du schon mal probiert mit -1? Resp. da es ein unsigned integer ist mit 0xFFFFFFFF? Das darunterliegende VISA API erkennt VI_TMO_INFINITE ganz eindeutig und es ist als 0xFFFFFFFF im C API definiert. Teste aber erst dass ein VISA Read mit indefinite timeout auch zurückkehrt wenn du die entsprechende Resource mit VISA Close abschliesst. Ansosnten hast Du keine Möglichkeit um eine soclhe Loop abzuschiessen wenn Du das Programm beenden willst. Rolf Kalbermatter Tasking Library - eg - 18.03.2009 14:33 ' schrieb:Hast Du schon mal probiert mit -1? Resp. da es ein unsigned integer ist mit 0xFFFFFFFF? Das darunterliegende VISA API erkennt VI_TMO_INFINITE ganz eindeutig und es ist als 0xFFFFFFFF im C API definiert. Teste aber erst dass ein VISA Read mit indefinite timeout auch zurückkehrt wenn du die entsprechende Resource mit VISA Close abschliesst. Ansosnten hast Du keine Möglichkeit um eine soclhe Loop abzuschiessen wenn Du das Programm beenden willst. Genau das ist das Problem. Es geht nicht. Man kann also das Lesen mit dem unendlichen Timeout nicht abbrechen. Aber es geht mit der Serial API. Da kann man Flush machen und das Lesen wird abgebrochen. Das ist bei VISA nicht der Fall, schade. Tasking Library - rolfk - 18.03.2009 15:20 ' schrieb:Genau das ist das Problem. Es geht nicht. Man kann also das Lesen mit dem unendlichen Timeout nicht abbrechen. Versuchs mal mit diesem VI! Keine Garantie dass es funktioniert aber rein theoretisch sollte es gehen. [attachment=17313] Rolf Kalbermatter Tasking Library - eg - 18.03.2009 15:30 Danke schön, ich habe es bei mir im User.lib abgespeichert, sobald ich es probiert habe, melde ich mich. Gruß, eg |