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!
Hallo zusammen,
ich krieg hier grad ne Krise. In einem VI habe ich 4 getaktete Schleifen. Ich dachte immer die laufen unabhängig voneinander. Ist waber nicht so. Wenn in Schleife 1 der Arbeitstakt 200ms ist macht Schleife 2 auch mal gerne eine Pause von 200 ms. Ich habe allen Schleifen einen eigenen Prozessor und Prioritäten zugeordnet. Was mache ich bloss falsch....
Gruss Volker
VI ist mittlerweile zu komplex - verschicken macht da keinen Sinn. Gerd: das ist mir schon klar. ich dachte parallel ist was anderes als nacheinander abarbeiten.
Vielleicht hättet ihr einen Vorschlag:
es geht um drei Prozesse die gleichzeitig ablaufen. Eine Bilderfassung mit einer Kamera (Belichtungszeit 100msec), eine Messwerterfassung von 4 Meßgrößen, eine Messwerterfassung von 2 Meßgrößen. Momentan läuft alles in einem VI (ja ja ich weiß, Schande über mein Haupt - ist halt im Laufe der Zeit immer mehr angewachsen). Jetzt muss das dringend mal sortiert werden. Meine Vorstellung: die drei Module laufen separat und unabhängig voneinander. Wie kriege ich das am besten hin. Die drei Module tauschen natürlich auch Daten aus und die Meßschleifen triggern auch Ereignisse in der Bilderfassungsschleife.
(20.05.2017 10:48 )Thermoman schrieb: Wie kriege ich das am besten hin.
Im Allgemeinen gilt: Am schönsten wären natürlich drei selbständige Prozesse.
Jeder Prozess ist ein VI, das selbständig läuft, also parallel zu allem anderen. Von solchen VIs kann man (theoretisch) beliebig viele laufen lassen. So ein VI ist sowas ähnliches wie eine Klasse: hat private (also gekapselte) Variablen. Hat Methoden, die aufgerufen werden können. Hat Eigenschaften, die abgerufen werden können. - Und hat selbstverständlich eine Schnittstelle. Gesteuert wird das VI mittels einer (als Zahl: 1, nicht 2, 3 oder 4, sondern nur 1) Queue, deren Daten in einem Cluster liegen: Mindestens ein Enumerator, der die Methode festlegt, die mal ausgeführt werden soll, sowie weitere an sich beliebige Daten. Das VI stellt per Melder, von denen es mehrere geben darf, Daten für den Rest der Wert zur Verfügung. Wenn, und das ist dann die meiste Zeit, gerade mal kein neuer Befehl per Queue reinkommt, führt das VI einen "Standard"-Case aus. Apropos Case: Das VI enthält "eigentlich nur" eine While-Schleife (sonst könnte das VI nicht permanent laufen), in der sich eine Case-Sequenz befinden. Außerhalb der Case-Sequenz wird die Queue abgefragt. Der "Standard"-Case ist dann z.B. der Case, in dem Daten gesampelt werden. Die erwähnten Methoden sind im übrigen die restlichen Cases ...
Eine ganz wichtige Sache:
So ein VI hat "kein Frontpanel". Das ist LabVIEW-technisch gesehen zwar falsch, Ablauf-technisch gesehen aber von Vorteil: Dieses VI zeigt keinerlei Daten selbst an. Zum Anzeigen ist nämlich keine Zeit. Anzeigen soll irgendwer, der die anzuzeigenden Daten ja per Melder abgreifen kann.
Zitat:Die drei Module tauschen natürlich auch Daten aus und die Meßschleifen triggern auch Ereignisse in der Bilderfassungsschleife.
Und hier liegt dann die Kunst.
* Bei zeitlich unkritischen Abläufen reicht es aus, Daten per Queue zu verschicken. Meine Klassen lesen alle 50ms (manche alle 10ms) die Queue aus und reagieren entsprechend.
* Bei kritischen Abläufen muss man dann doch wieder überlegen, ob man nicht doch zwei eigentlich unabhängige Abläufe in einem VI zusammenfasst. Normalerweise würde ich sagen: Pro Task eine Klasse. Außer z.B. wenn Zähler gesampelt werden sollen oder wenn "synchron" gesampelt werden muss.
* Eine weitere Möglichkeit, Ereignisse zu triggern, ist, (weitere) synchronisierende Elemente zu verwenden: z.B. Occurence-Funktionen. Die sind aber sehr speziell, ich selbst verwendet sie praktisch nicht.
Jeder, der zur wahren Erkenntnis hindurchdringen will, muss den Berg Schwierigkeit alleine erklimmen (Helen Keller).
Vielen Dank für deine sehr ausführliche Antwort. An diese Lösung hatte ich auch schon gedacht. Was hältst du davon eine große globale Variable anzulegen und hierüber den Austausch zu machen, wo ist hier eventuell der Nachteil gegenüber einer queue?
(21.05.2017 10:54 )Thermoman schrieb: Was hältst du davon eine große globale Variable anzulegen
- kurz: nix.
Zitat:wo ist hier eventuell der Nachteil
Erstens:
Je größer, desto schlechter. Mit größer meinst du bestimmt einen Cluster, bestehend aus allen möglichen Elementen.
Zweitens:
Anfällig für RaceConditions. Denksportaufgabe: Die Globale Variable muss ja irgendwann einmal geändert werden. Zum Ändern müssen die Daten ausgelesen ("Variable lesen"), mittels eines Datenflusses weitergeführt und irgendwie manipuliert, und schließlich wieder geschrieben werden ("Variable schreiben"). Was passiert, wenn genau in dem Moment, wenn sich die Daten im Fluss befinden, jemand anders auch genau diese Globale Variable ändern will? Das geht ohne weiteres, da LabVIEW parallel (im Sinne von Struktur), also Multitasking arbeitet. Einer von beiden wird als letzter Zurückgeschrieben haben - was ist dann mit dem Verarbeitungsergebnis des anderen?
Drittens:
Feinheiten, die ich nicht so genau kenne: Jede Instanz einer Globalen Variablen hat einen eigenen Speicherbereich (zumindest erinnere ich mich sowas mal gelesen zu haben). Bei großen GGVs wird natürlich viel Speicher verbraucht. Bedenke auch: Wenn das stimmt, werden beim Schreiben einer GV die Daten der GV auf alle Lesenden Instanzen kopiert. Ich hoffe mal, dass das in modernen LV-Version besser gemanagert wird.
Lösung:
Du musst also Vorkehrungen treffen, um zu verhindern, dass die selbe(!) Variable gleichzeitig von zwei Instanzen manipuliert werden kann. Das ist ganz einfach: Die Manipulation geschieht in einem SubVI mittels Methodenaufruf (das, was du ja schon kennst). Vorteil: Dieses SubVI kann nicht zweimal gleichzeitig ausgeführt werden, dafür nämlich sorgt LV intern. Dieses VI heißt dann FGV: "Funktionale Globale Variable".
Eine FGV besteht aus einen While-Schleife, in der sich eine Case-Sequenz befindet. Im einfachsten, also Standardfall, gilt: Die Bedingung der While-Schleife steht auf "Beenden". Die Schnittstelle des VIs ist sehr einfach: Ein(1) Ausgang mit dem Cluster der Daten. Ein(1) Eingang (strikt-typisierter) Enumarator, der die Methode angibt. Und ein(1) Eingang Variant, der unterschiedliche Daten enthalten kann, je nach Methode. Wenn man dann auch noch einen Case NONE hat (Standardmäßig Null), kann man den verwenden, um das VI aufzurufen, um lediglich die Daten am Ausgang zu bekommen, um sie am Bildschirm z.B. alle 500ms anzuzeigen. Vorteil: Man hat die Verarbeitung der Daten von der Anzeige getrennt.
Jeder, der zur wahren Erkenntnis hindurchdringen will, muss den Berg Schwierigkeit alleine erklimmen (Helen Keller).