Bei den meisten Anwendungen ist die Verwendung von Prioritätsstufen oder eines anderen Ausführungssystems als des Standardsystems, das die gleichzeitige Bearbeitung der VIs übernimmt, nicht notwendig. VIs werden standardmäßig im Standardausführungssystem mit normaler Priorität ausgeführt. Bei Multithread-Anwendungen bearbeitet ein separater Thread die Aktivitäten der Benutzeroberfläche, so dass die VIs von der Interaktion der Benutzeroberfläche isoliert werden. Das Ausführungssystem wechselt bei einer Anwendung mit nur einem Thread zwischen Benutzereingriffen und der Ausführung der VIs, wobei ähnliche Ergebnisse erzielt werden.

Im Allgemeinen besteht die beste Möglichkeit, die Ausführung zu bevorzugen darin, die Wartefunktion zu verwenden, um Schleifen mit geringerer Priorität in der Anwendung zu verlangsamen. Das ist besonders hilfreich bei Schleifen für VIs der Benutzeroberfläche, da eine Verzögerung von 100 bis 200 ms für den Nutzer kaum wahrnehmbar ist.

Verwenden Sie Prioritäten mit Bedacht. Wenn Sie VIs mit höherer Priorität erstellen, die eine Weile laufen, fügen Sie dem VI in weniger zeitkritischen Bereichen des Codes Wartezeiten hinzu, so dass sie die Zeit mit Tasks mit geringerer Priorität gemeinsam nutzen.

Seien Sie vorsichtig, wenn Sie globale und lokale Variablen oder andere externe Ressourcen, die andere Tasks verändern, bearbeiten. Mit Hilfe von Synchronisationsverfahren, wie zum Beispiel funktionale globale Variable oder Semaphor, lässt sich der Zugriff auf diese Ressourcen schützen.

Synchronisation des Zugriffs auf globale und lokale Variablen und externe Ressourcen

Da das Ausführungssystem mehrere Tasks parallel ausführen kann, muss darauf geachtet werden, dass auf globale und lokale Variablen sowie Ressourcen in der richtigen Reihenfolge zugegriffen wird.

Verhinderung von Laufzeitproblemen

Laufzeitprobleme können auf verschiedene Art und Weise verhindert werden. Am einfachsten ist es, nur eine einzige Stelle in der gesamten Anwendung zu haben, an der eine globale Variable geändert werden kann.

Bei einer Anwendung mit nur einem Thread, kann ein VI mit der Priorität "Unterprogramm" verwendet werden, um aus einer globalen Variable auszulesen oder in diese zu schreiben, ohne Laufzeitprobleme zu verursachen, da ein VI mit der Priorität "Unterprogramm" den Ausführungsthread nicht gemeinsam mit anderen VIs nutzt. Bei einer Multithread-Anwendung dagegen garantiert die Priorität "Unterprogramm" nicht den exklusiven Zugang zu einer globalen Variable, da ein anderes VI, das in einem anderen Thread ausgeführt wird, zur gleichen Zeit Zugriff auf die globale Variable haben kann.

Funktionale globale Variablen

Funktionale globale Variablen sind ablaufvariante VIs, die Schleifen mit nicht initialisierten Schieberegistern verwenden, um globale Daten zu halten. Eine funktionale globale Variable verfügt normalerweise über den Eingangsparameter Aktion, in dem festgelegt wird, welche Aufgabe das VI ausführt. Um mit globalen Variablen assoziierte Laufzeitprobleme zu vermeiden, können Sie funktionale globale Variablen verwenden, um kritische Abschnitte des Programmcodes, die eine Variable abfragen, zu schützen. Wenn Sie den Wert einer globalen Variable lesen, diesen Wert modifizieren und den Wert wieder in die Variable einfügen, könnenLaufzeitprobleme entstehen, da zwei Abschnitte parallelen Programmcodes, die gleichzeitig dieselbe Variable lesen, jeweils die Änderungen des anderen Codeabschnitts überschreiben können. Verwenden Sie funktionale globale Variablen, um Aktionen zur Änderung von Daten zu schützen. Funktionale globale Variablen können Laufzeitprobleme in kritischen Abschnitten verhindern, zum Beispiel bei Aktionen wie Lesen, inkrementieren und beim Schreiben von Daten in den Speicher oder bei Aktionen, die die Datenbank aktualisieren oder eine Datei modifizieren.

Die folgende Abbildung zeigt eine funktionale globale Variable, die eine einfache globale Variable zum Zählen implementiert. Das Ergebnis dieses Arbeitsschritts wird in einem nicht initialisierten Schieberegister in einer While-Schleife gespeichert. Die Aktionen in diesem Beispiel sind: initialisieren, lesen, inkrementieren und dekrementieren.

Bei jedem Aufruf des VIs wird das Blockdiagramm in der Schleife genau einmal ausgeführt. In Abhängigkeit von dem Parameter Aktion wird der Wert im Schieberegister durch den Case in der Schleife initialisiert, nicht geändert, jeweils um eins erhöht oder um eins verringert.

Funktionale globale Variablen können, wie beschrieben, zur Implementierung einfacher globaler Variablen verwendet werden. Sie sind jedoch besonders nützlich, wenn komplexere Datenstrukturen wie Stack- oder Queue-Puffer implementiert werden sollen. Sie können mit Hilfe von funktionalen globalen Variablen auch den Zugriff auf globale Ressourcen schützen (z. B. Dateien, Messgeräte und DAQ-Geräte), die nicht durch eine globale Variablen dargestellt werden können, da Aufrufe der funktionalen globalen Variablen sequenziell ausgeführt werden, es sei denn, das VI ist ablaufinvariant.

Die meisten Synchronisationsprobleme können durch funktionale globale Variablen gelöst werden, da die funktionalen globalen VIs dafür sorgen, dass zu einer bestimmten Zeit nur ein einziger Aufruf die enthaltenen Daten ändert. Ein Nachteil dieser funktionalen globalen Variablen besteht allerdings darin, dass bei Änderungen der Art und Weise, wie Ressourcen modifiziert werden, das Blockdiagramm des funktionalen globalen VIs ebenfalls geändert werden und eine neue Aktion hinzugefügt werden muss. In einigen Anwendungen, in denen die verwendeten globalen Ressourcen häufig geändert werden, können diese Änderungen zu Unannehmlichkeiten führen. Erstellen Sie in solchen Fällen die Anwendung so, dass ein Semaphor verwendet wird, um den Zugriff auf die globale Ressource zu schützen.

Methoden des Datenaustauschs Startseite

Semaphore

Ein Semaphor, auch Mutex genannt, ist ein Objekt zum Schutz vor dem Zugriff auf gemeinsame Ressourcen, wie z. B. globale Variablen. Der Programmabschnitt, der auf die gemeinsame Ressource zugreift, wird als kritischer Abschnitt bezeichnet. Semaphore schützen den Zugriff auf kritische Abschnitte, indem nur eine bestimmte Anzahl an Tasks gleichzeitig auf das Semaphor zugreifen können. In der Regel soll nur ein Task zu einer bestimmten Zeit auf den kritischen Abschnitt zugreifen, der durch einen gemeinsamen Semaphor geschützt wird. Semaphore lassen sich so konfigurieren, dass sie mehreren Tasks (bis hin zu einem vordefinierten Grenzwert) den Zugriff auf einen kritischen Abschnitt gewähren.

Für die meisten Anwendungsfälle von Semaphoren sind die folgenden Schritte notwendig:

  1. Erkennen des kritischen Abschnitts —Mit Hilfe von Semaphoren lässt sich der Zugriff auf Programmabschnitte steuern, die auf gemeinsame Ressourcen zugreifen. Wenn z. B. mehrere SubVIs mit derselben globalen Variablen arbeiten, müssen Sie zum Vermeiden von Laufzeitproblemen sicherstellen, dass diese Programmabschnitte nicht gleichzeitig ausgeführt werden. In diesem Beispiel ist jeder Programmabschnitt zum Lesen oder Schreiben der globalen Variablen ein kritischer Abschnitt. Weitere Beispiele für Programmabschnitte, die als kritisch bezeichnet werden, sind Datei- und Gerät-I/O.
  2. Erstellen eines Semaphors für die kritischen Abschnitte—Erstellen Sie mit Hilfe des VIs Semaphorreferenz anfordern ein neues Semaphor oder rufen Sie ein vorhandenes Semaphor ab. Per Voreinstellung kann ein neues Semaphor jeweils nur von einem Task belegt werden. Wenn mehr Tasks zur gleichen Zeit Zugriff auf das Semaphor haben sollen, legen Sie die gewünschte Anzahl der Tasks am Eingang Größe des VIs "Semaphorreferenz anfordern" fest.
  3. Zugriff auf das Semaphor vor jedem kritischen Abschnitt—Fordern Sie mit Hilfe des VIs Semaphor belegen den Zugriff auf das Semaphor an. Wenn das Semaphor von einem anderen Task verwendet wird, hält der Datenfluss am VI "Semaphor belegen" an, bis der andere Task das Semaphor freigibt. Wenn ein Programmabschnitt den Zugriff auf ein Semaphor erlangt hat, kann bis zur Freigabe des Semaphors kein anderer Task auf das Semaphor zugreifen. Daher wird die Ausführung des geschützten Programmabschnitts zwischen dem VI "Semaphor belegen" und dem VI "Semaphor freigeben" garantiert beendet, bevor die Ausführung eines anderen geschützten Abschnitts beginnt.
  4. Freigabe des Semaphors nach jedem kritischen Abschnitt—Geben Sie mit Hilfe des VIs Semaphor freigeben den Zugriff auf das Semaphor frei, sodass ein anderer Task, der auf das Semaphor wartet, Zugriff erlangen und seinen eigenen kritischen Programmabschnitt ausführen kann.
  5. Freigabe der Referenz auf das Semaphor—Geben Sie mit Hilfe des VIs Semaphorreferenz freigeben die Referenz auf das Semaphor frei. Zur effizienten Verwendung von Systemressourcen sollte eine Semaphorreferenz freigegeben werden, sobald sichergestellt ist, dass kein Task mehr das Semaphor benötigt.
Hinweis Bei manchen fortgeschrittenen Anwendungsfällen für Semaphore kann auf das Erfassen und Freigeben des Semaphors im selben Programmabschnitt verzichtet werden.

Ein Beispiel zur Verwendung der VIs "Semaphorreferenz anfordern" und "Semaphorreferenz freigeben" finden Sie im VI "Simple Semaphore.vi" im Verzeichnis labview\examples\Synchronization\Semaphore.

In der folgenden Abbildung wird dargestellt, wie sich die kritischen Abschnitte mit einem Semaphor schützen lassen. Ein anderes VI hat das Semaphor erstellt und leitet die Referenz auf diese SubVIs weiter. Das Semaphor hat eine Größe von 1. Das heißt, nur ein Task kann das Semaphor zu einer bestimmten Zeit belegen.

Alle vorherigen Blockdiagramme enthalten einen kritischen Abschnitt für den Zugriff auf dieselbe globale Variable (Anzahl). Daher verwenden die Blockdiagramme dasselbe Semaphor. Bevor ein Blockdiagramm den kritischen Abschnitt ausführt, wird das VI Semaphor belegen aufgerufen, um zu ermitteln, ob das andere Blockdiagramm bereits Zugriff auf das Semaphor hat. Wenn das Semaphor belegt ist, wartet das VI "Semaphor belegen" bis das Semaphor verfügbar wird. Wenn das Semaphor verfügbar wird, gibt das VI "Semaphor belegen" den Wert FALSE für Timeout aus. Damit wird angezeigt, dass das Blockdiagramm die Berechtigung zur Ausführung des kritischen Abschnitts hat. Wenn das Blockdiagramm die Ausführung des kritischen Abschnitts beendet, gibt das VI Semaphor freigeben das Semaphor frei und ein anderes wartendes Blockdiagramm kann mit der Ausführung beginnen.

Lebensdauer eines Semaphors

Ein Semaphor verbleibt so lange im Speicher, wie ein Top-Level-VI, das sich nicht im Ruhestand befindet, eine Referenz auf das Semaphor hat. Wenn sich das Top-Level-VI im Ruhezustand befindet, werden alle Referenzen auf Semaphore des VIs freigegeben, einschließlich der Referenzen in SubVIs des Top-Level-VIs. Wenn die letzte Referenz auf ein benanntes Semaphor freigegeben wird, zerstört LabVIEW die Semaphore. Da nur eine Referenz auf ein unbenanntes Semaphor erstellt werden kann, wird ein unbenanntes Semaphore zerstört, wenn sich das Top-Level-VI im Ruhezustand befindet. Zum Verwenden eines Semaphors in verschiedenen Top-Level-VIs, benennen Sie das Semaphore und rufen Sie das VI "Semaphorreferenz anfordern" von jedem Top-Level-VI auf, so dass jedes VI seine eigene eindeutige Referenz zum Semaphor anfordert.