User Tools

Site Tools


userpages:wolfgangk:subparameter

Mehrfacher "paralleler" Aufruf einer Bibliotheks-Funktion mit Übergabewerten

Userpages - Wolfgang (WolfgangK)

Im Folgenden wird mit einem Skript-Beispiel gezeigt, wie bei mehrfachen ("gleichzeitigen"1)) Aufrufen einer Funktion Übergabewerte in Variablen (Ein- und Ausgabeparameter) mitgegeben werden können, die sich trotz "gleichzeitiger" Ausführung der Funktion nicht gegenseitig überschreiben.

Um dies zu erreichen, müssen bei jedem Aufruf der Funktion andere Variablennamen verwendet werden. In Rocrail können für diesen Zweck die Variablennamen so "gebaut" werden, dass sie erst kurz vor der Ausführung der Funktion ihren endgültigen Namen erhalten. Dafür werden in den Variablennamen eingebaute Variablen (wie z. B. "%callerid%" und "%state%") verwendet, die erst kurz vor der Ausführung des Skripts durch "feste Werte" ersetzt werden.

Eine Variable, in der z. B. die ID einer Lok gespeichert werden soll, könnte also wie folgt benannt werden:

<vr id="Lok_%callerid%_%state%" text="V200" value="0" generated="true"/> 

Wenn dann der Rückmelder "fb01" beim Status "on" ein Skript aufruft, das diese Variable enthält, dann erhält diese Variable im Augenblick der Aufrufs den Namen "Lok_fb01_on".

Da ein Skript meist bei der Statusänderung eines Rocrail-Objekts (z. B. bei Auslösen eines Rückmelders) aufgerufen wird, macht es in den meisten Fällen Sinn, die eingebauten Variablen "%callerid%" und "%state%" in den Variablennamen zu verwenden, da diese beiden Variablen dann den jeweiligen Objektnamen und Status enthalten.

Wie dieses Prinzip des "Namensaufbaus" für Funktionsaufrufe aus Funktionsbibliotheken, wie z. B.

<sub file="Funktionsbibliothek.xml" id="addiere_1"/>

verwendet werden kann, wird im folgenden Beispiel gezeigt.

Beispiel

In diesem Beispiel (alle Beispieldateien zum Herunterladen: mehrfachaufruf_funktion.zip)

mehrfachaufruf_funktion_rocview-fenster.jpg

wird beim Auslösen von jedem der zwei Rückmelder ("fb111" und "fb999") per Aktion ein Skript ausgeführt: Bei "on" von "fb111" das Skript "Aktion_fb111.xml" und bei "on" von "fb999" das Skript "Aktion_fb999.xml".

In jedem der beiden Skripte wird einer Variablen ein Wert zugewiesen und dies im Trace protokolliert. Danach wird in jedem Skript die gleiche Funktion

<sub file="Funktionsbibliothek.xml" id="addiere_1"/>

aufgerufen, die den Wert dieser Variable um eins erhöht. Im letzten Schritt wird diese Variable mit dem neuen Wert wieder im Trace protokolliert.

Als Name für die Variable, die an die Funktion übergeben wird, wurde "subparam_add1_%callerid%_%state%" gewählt. Außerdem wird in dieser Funktion 2 Sekunden gewartet, um testen zu können, was passiert, wenn diese Funktion während des Wartens ein weiteres Mal durch Aktivieren des zweiten Rückmelders aufgerufen wird.

Im Skript "Aktion_fb111.xml" erhält diese Variable zu Beginn den Wert "3" und in "Aktion_fb999.xml" den Wert "7".

Zum Testen wird zunächst der Rückmelder "fb111" ausgelöst und dann (möglichst innerhalb von 2 Sekunden) der Rückmelder "fb999". Im Trace wird dann Folgendes aufgelistet:

..295 !!! Start Aktion_fb111: subparam_add1_fb111_on hat den Wert 3
..766 !!! Start Aktion_fb999: subparam_add1_fb999_on hat den Wert 7
..301 ... Ende Aktion_fb111: subparam_add1_fb111_on hat den Wert 4
..771 ... Ende Aktion_fb111: subparam_add1_fb999_on hat den Wert 8

Wie man sieht, werden die Skripte "ineinander verzahnt" ausgeführt und es werden unterschiedliche Variablennamen verwendet. Am Ende hat die Variable in "Aktion_fb111.xml" den Wert "4" die Variable in "Aktion_fb999.xml" den Wert "8".

Weiter unten wird dieses Beispiel noch einmal aufgegriffen, um etwas detaillierter darzustellen, was bei der Ausführung dieser Skripte im Einzelnen passiert.

Wie kann man sich den internen Ablauf bei solchen Skriptaufrufen vorstellen?

Um die oben beschriebene Variablenbenennug in eigenen Skripten anwenden zu können, kann es helfen, sich eine ungefähre Vorstellung vom internen Ablauf zu machen. Dabei muss diese Vorstellung nicht genau dem tatsächliche Ablauf der internen Verarbeitung von Rocrail entsprechen. Um zu verstehen, welche Auswirkungen die Skriptbefehle auf den Ablauf und das Ergebnis eines Skripts haben, genügt hier eine "grobe" Sicht auf den Ablauf. Wenn wir unter diesem Gesichtspunkt den Ablauf eines Skripts ansehen, können wir folgendes feststellen.

Bevor die eigentliche Abarbeitung der einzelnen Skript-Befehle startet, wird das Skript in zwei vorgeschalteten Arbeitsschritten erst noch "vorbereitet".

  • In einem ersten Schritt werden alle "sub"-Befehlen durch den Quelltext der hier aufgerufenen Funktion ersetzt.
  • Im zweiten Schritt werden alle eingebauten Variablen (also alle %-Variablen) durch ihre zu diesem Zeitpunkt aktuellen Werte ersetzt.
  • Erst danach wird das so vorbereitete Skript Befehl für Befehl ausgeführt.

Auf diese Weise erhalten alle Benutzer-Variablen (also die, die mit "@" oder "#" beginnen), in deren Namen %-Variablen verwendet wurden, einen festen Namen, der nur für diese eine Ausführung des Skripts Bestand hat. Der Name dieser Benutzer-Variablen ändert sich also im Laufe dieser einen Ausführung des Skripts nicht mehr. (Im Gegensatz zum Inhalt dieser Benutzer-Variablen, der sich natürlich ändern kann und soll.)

Wird dann nahezu zeitgleich ein weiteres Skript aufgerufen, das den gleichen "sub"-Befehl enthält, wird eine neue temporäre Version dieses Skripts mit anderen Variablennamen erzeugt und ausgeführt. Das zuerst aufgerufenen Skripte braucht dann noch nicht beendet worden sein.

Da in diesen beiden temporäre Skriptenversionen unterschiedliche Namen verwendet werden, kommt es zu keinen gegenseitigen Variablenüberschreibungen, auch wenn diese temporären Skriptversionen "gleichzeitig" ausgeführt werden.

Beispiel

Wenn im obigen Beispiel der Rückmelder "fb111" ausgelöst wird, sehen diese vorgeschalteten Arbeitsschritte wie folgt aus.

Ausgehend vom ursprünglichen Quelltext von "Aktion_fb111.xml" (hier werden nur die für diese Erläuterung relevanten Skriptzeilen zitiert)

<xmlscript desc="Aktion_fb111.xml">
  <vr id="subparam_add1_%callerid%_%state%" text="" value="3" generated="true"/>
  <trace text="!!! Start Aktion_fb111: subparam_add1_%callerid%_%state% hat den Wert #subparam_add1_%callerid%_%state%"/>	

  <sub file="Funktionsbibliothek.xml" id="addiere_1"/>		

  <trace text="... Ende Aktion_fb111: subparam_add1_%callerid%_%state% hat den Wert #subparam_add1_%callerid%_%state%"/>
  <vr id="Zaehler_Aktion_fb111" value="0"/>
</xmlscript>

und vom Quelltext der aufgerufenen Funktion "addiere_1"

<xmlscript desc="Funktionsbibliothek.xml">
  <function id="addiere_1">
  <sleep time="2000"/>
  <vr id="subparam_add1_%callerid%_%state%" text="" value="#subparam_add1_%callerid%_%state% + 1" generated="true"/>
  </function>
</xmlscript>

wird im ersten Vorbereitungsschritt in "Aktion_fb111.xml" der "sub"-Befehl ersetzt:

<xmlscript desc="Aktion_fb111.xml">
  <vr id="subparam_add1_%callerid%_%state%" text="" value="3" generated="true"/>
  <trace text="!!! Start Aktion_fb111: subparam_add1_%callerid%_%state% hat den Wert #subparam_add1_%callerid%_%state%"/>	
  
  <sleep time="2000"/>
  <vr id="subparam_add1_%callerid%_%state%" text="" value="#subparam_add1_%callerid%_%state% + 1" generated="true"/>
  
  <trace text="... Ende Aktion_fb111: subparam_add1_%callerid%_%state% hat den Wert #subparam_add1_%callerid%_%state%"/>
  <vr id="Zaehler_Aktion_fb111" value="0"/>
</xmlscript>

Im zweiten Vorbereitungsschritt werden dann alle %-Variablen ersetzt:

<xmlscript desc="Aktion_fb111.xml">
  <vr id="subparam_add1_fb111_on" text="" value="3" generated="true"/>
  <trace text="!!! Start Aktion_fb111: subparam_add1_fb111_on hat den Wert #subparam_add1_fb111_on"/>	
  
  <sleep time="2000"/>
  <vr id="subparam_add1_fb111_on" text="" value="#subparam_add1_fb111_on + 1" generated="true"/>
  
  <trace text="... Ende Aktion_fb111: subparam_add1_fb111_on hat den Wert #subparam_add1_fb111_on"/>
  <vr id="Zaehler_Aktion_fb111" value="0"/>
</xmlscript>

Danach werden die so vorbereiteten Skriptbefehle abgearbeitet.

Auf die gleiche Weise wird auch das Skripte "Aktion_fb999.xml" vorbereitet, wenn "fb999" ausgelöst wird. Im ursprünglichen Quelltext (auch hier werden nur die für diese Erläuterung relevanten Skriptzeilen zitiert)

<xmlscript desc="Aktion_fb999.xml">
  <vr id="subparam_add1_%callerid%_%state%" text="" value="7" generated="true"/>
  <trace text="!!! Start Aktion_fb999: subparam_add1_%callerid%_%state% hat den Wert #subparam_add1_%callerid%_%state%"/>	
  
  <sub file="Funktionsbibliothek.xml" id="addiere_1"/>		
  
  <trace text="... Ende Aktion_fb111: subparam_add1_%callerid%_%state% hat den Wert #subparam_add1_%callerid%_%state%"/>
  <vr id="Zaehler_Aktion_fb999" value="0"/>
</xmlscript>

wird zuerst der "sub"-Befehl ersetzt

<xmlscript desc="Aktion_fb999.xml">
  <vr id="subparam_add1_%callerid%_%state%" text="" value="7" generated="true"/>
  <trace text="!!! Start Aktion_fb999: subparam_add1_%callerid%_%state% hat den Wert #subparam_add1_%callerid%_%state%"/>	
  
  <sleep time="2000"/>
  <vr id="subparam_add1_%callerid%_%state%" text="" value="#subparam_add1_%callerid%_%state% + 1" generated="true"/>
  
  <trace text="... Ende Aktion_fb111: subparam_add1_%callerid%_%state% hat den Wert #subparam_add1_%callerid%_%state%"/>
  <vr id="Zaehler_Aktion_fb999" value="0"/>
</xmlscript>

und danach alle %-Variablen

<xmlscript desc="Aktion_fb999.xml">
  <vr id="subparam_add1_fb999_on" text="" value="7" generated="true"/>
  <trace text="!!! Start Aktion_fb999: subparam_add1_fb999_on hat den Wert #subparam_add1_fb999_on"/>	
  
  <sleep time="2000"/>
  <vr id="subparam_add1_fb999_on" text="" value="#subparam_add1_fb999_on + 1" generated="true"/>
  
  <trace text="... Ende Aktion_fb111: subparam_add1_fb999_on hat den Wert #subparam_add1_fb999_on"/>
  <vr id="Zaehler_Aktion_fb999" value="0"/>
</xmlscript>

Ein Vergleich der letztendlich ausgeführten (temporären) Skriptbefehle von "Aktion_fb111.xml" und "Aktion_fb999.xml" zeigt, dass unterschiedliche Variablennamen verwendet werden und diese deshalb auch nicht gegenseitig überschrieben werden können.

1)
"gleichzeitig" ist nicht ganz zutreffend. Eher ist es so, dass nacheinander mal ein Befehl des einen und dann des anderen Skripts ausgeführt wird.
userpages/wolfgangk/subparameter.txt · Last modified: 2023/04/21 20:27 by wolfgangk