Jump to content

Unerwartetes Ergebnis, wenn ein Event zwei abhängige Ereignisse auslöst


Andreas66
 Share

Recommended Posts

Hallo,

die Anlage die ich gerade aufbaue hat ein Problem mit der Ereignisverarbeitung, wodurch es immer wieder zu Unfällen kommt. Ich konnte das Problem auf eine Anlage mit nur zwei Weichen und einem Taster reduzieren, so dass es leichter nachvollziehbar ist. (siehe Anhang)

Die Idee ist folgende:
Ich habe zwei Weichen, nennen wir sie A und B. Durch einen gemeinsamen Schalter können beide Weichen in die Position "0" geschaltet werden, was aber nur erlaubt ist, wenn die jeweils andere in der Position "1" steht.

Tatsächlich passiert jetzt aber folgendes:
Sind beide Weichen in der Position "1", so wird die Weiche A in die Position "0" geschaltet. (OK) Die Weiche "B" wird aber auch in die Position "0" geschaltet, wodurch dann beide Weichen in Position "0" stehen, was es eigentlich nicht geben dürfte.

Entweder gibt es bei der Ereignisverarbeitung eine Parallelverarbeitung, so dass beide Ereignisse gleichzeitig abgearbeitet werden oder Innerhalb eines Ereignisses wirken sich Änderungen in der Weichenstellung nicht auf die Bedingungen anderer Ereignisse aus.

Ich hoffe ich habe das verständlich beschrieben. Im Zweifelsfall bitte nachfragen.

Es wäre nett, wenn mir jemand die Arbeitsweise der Ereignisverarbeitung soweit erklären könnte, dass klar wird, warum dieses Beispiel nicht wie erwartet funktionieren kann und ich mir überlegen kann, was ich dagegen tun kann.

 

Zum Verständnis: Die Beispielanlage mit zwei Weichen ist so natürlich sinnlos, da eine Weiche niemals schalten würde, wenn es so funktionieren würde, wie ich es erwartet hätte. Es ist aber einfach die kleinst mögliche Anlage, mit der ich mein Problem erklären kann.

 

Andreas

 

Racecondition.zip

Link to comment
Share on other sites

Hallo Andreas,

die EV arbeitet folgendermaßen:

  1. Tritt ein Ereignis ein, werden zunächst alle in der EV hinterlegten Ereignisse mit den Bedingungen geprüft
  2. Alle Aktionen der erfüllten Bedingungen werden in einer Liste gesammelt
  3. Die gesammelten Aktionen werden der Reihe nach ausgeführt

Das erklärt, warum deine beiden Ereignisse "gleichzeitig" auftreten, weil das Umschalten der Weichen erst nach Prüfung ALLER Ereignisse/Bedingungen stattfindet. Dieser Ablauf ist wichtig, um Endlosschleifen zu vermeiden, da Aktionen ja neue Ereignisse auslösen könnten.

Ist der Zustand "Beide Weichen auf 1" denn ein gültiger Zustand bei dir? Wer entscheidet denn dann, welche der beiden Weichen auf 0 geschaltet wird, wenn die Taste gedrückt wird? Oder haben die Weichen in der Realität immer einen entgegengesetzten Zustand?

Viele Grüße,

Neo

Link to comment
Share on other sites

Hallo Neo,

danke für die Erklärung, damit leuchtet mir dann auch ein, was auf meiner Anlage passiert.

Das Beispiel mit den zwei Weichen ist natürlich Blödsinn. Es ging mir nur darum in einem ganz einfachen Beispiel zu verdeutlichen, was passiert. Das reale Szenario ist etwas komplexer (siehe Bild).

Beteiligt sind drei Signale und mehrere Weichen. Aus den Richtungen A, B und C können Züge kommen und sie sollen auf die Gleise D und E verteilt werden. Je nachdem, welches der Ziel-Gleise gerade Platz hat, soll der Zug auf das entsprechende Gleis geleitet werden oder auch warten, wenn kein Gleis frei ist. Das klappt eigentlich auch ganz gut, nur manchmal kommt es vor, wenn mehrere Züge gleichzeitig eintreffen, dass zwei Züge gleichzeitig für das gleiche Gleis freigeschaltet werden und dann kracht es eben.

Andreas

 

 

Wege.jpg

Link to comment
Share on other sites

Hallo Andreas,

ich glaube, dass Du bei Deinem Beispiel um einen "Lock" (d.h. um einen Serialisierungs-Mechanismus) nicht herumkommen wirst. Denn der Lock ist dazu da, mehrere gleichzeitig um dasselbe Betriebsmittel (in Deinem Fall die Gleise D und E und die davor befindlichen Weichenstraßen) konkurrierende Anforderer (in Deinem Fall die auf den Gleisen A, B uncd C ankommenden Züge) gegebenenfalls so zu verzögern, dass zu einem Zeitpunkt stets nur einem Anforderer ein Betriebsmittel zur Verfügung gestellt wird (das ist dann die "Serialisierung").

Bitte schau Dir mal im Wiki die Beschreibung "Automatische Zugsteuerung mit der Ereignisverwaltung" an. Dort findest Du insbesondere den Abschnitt "Realisierung eines Lock-Mechanismus mittels einer Variable der Ereignisverwaltung", in dem genau beschrieben ist, wie man einen Lock anlegt und verwendet. In den weiteren Abschnitten findest Du dann "Fallbeispiele", wie man Strecken(-Betriebsmittel) den darum konkurrierenden Zügen korrekt und sicher zuteilt.

Viele Grüße
BahnLand

P.S.:
Jetzt hat mich Quackster überholt. Das von ihm genannte Beispiel ist eine konkrete Anwendung der von mir genannten Wiki-Abschnitte.

Link to comment
Share on other sites

In meiner Lösung ist natürlich auch ein Lock drin, sonst käme es ja immer zum absoluten Chaos. Das Problem tritt auf, wenn zwei Ereignisse gleichzeitig auftreten, weil dann, wie Neo oben erklärt hat, beide Ereignisse den selben Lock-Zustand signalisiert bekommen, obwohl beide Ereignisse den Lock verändern.

Nehmen wir mal das Beispiel, auf den Gleisen A und B wartet ein Zug für die Ausfahrt nach Gleis E. Die Event Bescheibung sieht dann so aus

Ereignis 1: Zug auf Gleis A wartet.
Bedingung: Lock nicht gesetzt.
Aktion: Lock setzen / Zug A nach E freischalten

Ereignis 2: Zug auf Gleis B wartet
Bedingung: Lock nicht gesetzt.
Aktion: Lock setzen / Zug B nach E freischalten

Treten jetzt beide Ereignisse gleichzeitig auf, dann passiert nach Neos Beschreibung folgendes:

Ereignis 1 ist aufgetreten und die Bedingung ist erfüllt. Die Aktionen "Lock setzen" und "Zug A nach E freischalten" werden in einer Liste vermerkt aber noch nicht ausgeführt.
Ereignis 2 ist gleichzeitig aufgetreten und die Bedingung ist ebenfalls erfüllt (Bitte bedenken: Das "Lock setzen" wurde nur vermerkt aber noch nicht ausgeführt). Die Aktionen "Lock setzen" und "Zug B nach E freischalten" werden in einer Liste vermerkt.

Jetzt wird alles der Reihe nach ausgeführt:

- Lock setzen
- Zug A nach E freischalten
- Lock setzen
- Zug B nach E freischalten

und schon krachen die Züge zusammen.

Der Lock ist zwar notwendig, für das Problem aber nicht die Lösung. Die Lösung sieht hier so aus, dass verhindert werden muss, dass die beiden Ereignisse gleichzeitig auftreten. In meinem speziellen Fall sieht das so aus:
Ich habe einen Timer, der alle 500ms einen Schalter betätigt. Schaltet der Schalter auf "An", so wird Gleis "A" überprüft. Schalter der Schalter auf "Aus", so wird Gleis "B" überprüft. Damit ist sichergestellt, dass die Ereignisse nicht zeitgleich erfolgen können und zu dem Konflikt kann es nicht mehr kommen. Jetzt muss ich nur noch von einem Schalter auf einen Zähler Upgraden, da es ja drei Einfahrtsbereiche gibt, weswegen ich drei Zustände brauche.

 

Andreas

P.S.: Im Endeffekt kommt die Geschichte mit dem Schalter aber auf das Gleiche raus, wie die Beschreibung des Timers für den Lock im Wiki Artikel

Link to comment
Share on other sites

Hallo Andreas,

wenn ich Dein Szenario richtig durchschaue, gibt es da einen  "Denkfehler":
Du darfst die Aktionen "Lock setzen" und "Zug freischalten" nicht in einer Aktionsgruppe starten, sondern Du musst zwingend nach dem Setzen des Locks zuerst einmal überprüfen, ob der Lock dem Zug auch wirklich definitiv zugeteilt wurde (also die Lock-Variable auch wirklich jenen Wert besitzt, die für den jeweiligen Zug zutreffend ist). Denn nur so kannst Du verhindern, dass die konkurrierenden Züge (egal ob 2, 3 oder mehr) gleichzeitig losfahren. Wichtig ist, dass Du zwischen dem Setzen des Locks und dem Überprüfen eine kleine Wartezeit verstreichen lässt (den Bruchteil einer Sekunde), um sicherzustellen, dass entweder andere Konkurrenten über das "bedingte" Setzen des Locks daran gehindert werden, den Lock selbst zu setzen, oder, wenn die Bedingungs-Abfrage mehrerer Konkurrenten wegen der Gleichzeitigkeit zum selben Ergebnis "frei" geführt hat, ein mögliches Überschreiben des selbst gesetzten Locks durch einen Konkurrenten erkannt wird. Letztendlich kann nämlich in der Lock-Variable nur ein Wert (also die Zuweisung des Locks für genau einen konkurrierenden Zug) drin stehen. Und nach der kleinen Wartezeit-Pause ist sichergestellt, dass keine Überschreiber mehr folgen. Also kann dann eindeutig festgestellt werden, welcher Zug den Lock bekommen hat. Und das kann dann eben auch ein anderer Zug sein, als jener, der meint, seinen Lock erfolgreich gesetzt zu haben. In diesem Fall war das Setzen des Locks doch nicht erfolgreich, weshalb der Zug eben dann auf die nächste Freigabe des Locks warten muss.

Also nochmals formal zusammengefasst:

  1. Es gibt zwei Typen von Auslösern für die mögliche Anforderung des Locks für die auf den Gleisen A bis C die EInfahrt in die Gleise D oder E wünschenden Züge:
    a) Die Anforderung aufgrund der Einfahrt in eines der Gleise A bis C
    b) Die Freigabe des Locks durch den Zug, der ihn gerade belegt hat.
  2. Mit der Auslösung des Bedarfs, in eines der Gleise D oder E einzufahren, muss die tatsächliche Weiterfahrt durch die Belegung des Locks abgesichert werden. Hierzu wird die Zuweisung des "eigenen" Werts für die Lock-Variable an die Bedingung geknüpft, dass der Lock (die Lock-Variable) momentan frei ist.
  3. Der Lock kann hier gleichzeitig von mehreren Konkurrenten überschrieben werden, weil, wie Du zutreffend bemerkt hast, die Konkurrenten bei Gleichzeitigkeit alle den Lock als frei erkennen können. Deshalb genügt es nicht, den Lock zu setzen und dann gleich loszufahren.
  4. Durch ein kurzzeitiges Warten (z.B. 0,2 Sekunden) wird sichergestellt, dass das Überschreiben des selbst gesetzten Locks durch mögliche Konkurrenten noch erkannt wird, oder diese nicht mehr in der Lage sind, den Lock zu überschreiben. D.h. nach Ablauf der Wartezeit besitzt die Lock-Variable einen eindeutigen Wert, der nun von "zeitgleichen" Konkurrenten nicht mehr abgeändert werden kann, und der entweder den Anforderer selbst oder aber einen jener Konkurrenten als gültigen Lock-Inhaber indentifiziert.
  5. Nur wenn die Lockvariable nun den "eigenen" Wert enthält, darf der Zug in eines der Gleise D oder E starten. Und das ist nun auch wirklich nur ein Zug, weil die konkurrierenden Züge ihren Wert in der Lock-Variable nicht vorgefunden haben.

Wenn Du Dich an diese Vorgehensweise hältst, solltest Du mit Deinem Lock keine Probleme mehr haben. Beachte jedoch bitte, dass Du mit dem Lock nicht nur die Gleise D und E, sondern auch die davor liegende, von den einfahrenden Zügen aus den Gleisen A bis C zu benützende Weichenstraße schützen musst.

Also: Lock schützt die Phase vom Beginn der Ausfahrt des Zuges aus Gleis A, B oder C über das Passieren der Weichenstraße bis zum Abschluss der Ankunft in einem der Zielgleise D oder E.

Viele Grüße
BahnLand

Link to comment
Share on other sites

Hallo BahnLand,

ich glaube nicht, dass in meiner Lösung ein Denkfehler drin ist, wir haben nur unterschiedliche Ansätze.

Die ursprüngliche Lösung (Eröffnungspost) war falsch, da ich nicht wusste, dass Ereignisse tatsächlich parallel verarbeitet werden. In der aktuellen Lösung funktioniert es aber. Ich will nochmal meinen Ansatz erläutern:

Ich verwende einen Takt. Dabei ist der Takt dreistufig. In Takt 1 wird die Freigabe für A überprüft. In Takt 2 die Freigabe für B und in Takt 3 die Freigabe für C. Danach geht es wieder mit Takt 1 los.

In jedem Takt wird dann überprüft, ob eine konkurrierende Fahrstraße besteht. Ist dies nicht der Fall, so wird die gewünschte Fahrstraße geschaltet und das Signal auf Grün gestellt.

Nehmen wir mal ein Beispiel:
Vor den Signalen B und C wartet ein Zug und beide wollen nach D. Dann passiert folgendes:

Takt 1: Es passiert rein gar nichts
Takt 2: Es wird die Fahrstraße von B nach D geschaltet und B bekommt grün
Takt 3: Es passiert wieder gar nichts, da es eine konkurrierende Fahrstraße von B nach D gibt.

Irgendwann hat der Zug von B dann den Bereich verlassen. Sobald wir wieder mal in Takt 3 sind, bekommt auch der Zug C seine Freigabe. Allerdings kann es sein, dass es zwischenzeitlich eine andere Fahrstraße wird, da in jedem Takt Durchlauf überprüft wird, welche Fahrstraßen möglich ist.

Andreas

 

Link to comment
Share on other sites

Hallo Andreas,

Du hast in Deiner vorherigen Nachricht geschrieben:

Zitat

Der Lock ist zwar notwendig, für das Problem aber nicht die Lösung.

Hierauf hat sich mein Hinweis auf einen Denkfehler bezogen. Denn ein "sauberer" Lock-Mechanismus muss, wenn er funktionieren soll, den nachträglichen Bestätigungs-Test beinhalten. Da Deine Realisierung des Locks also "nicht vollständig" ist, benötigst Du zusätzlich die "Separierungs-Schleife", mit der Du die eigentlich mögliche parallele Abfrage eventuell konkurrierender Züge schon vom vornherein auseinander ziehst. Damit - und hier hast Du Recht - schließt Du mögliche Konkurrenzen von vornherein aus, was dann die Bestätigungs-Abfrage erübrigt.

Ist meine Annahme richtig, dass Deine "Prüftakt"-Schleife immer läuft - unabhängig davon, ob in den Gleisen A bis C wartende Züge vorhanden sind oder nicht? Und ist es weiterhin richtig, dass Du für jede Anzahl konkurrierender Züge (Gleise) den Algorithmus funktional anpassen musst?

Bei der Anwendung des "vollständigen" Lock-Mechanismus hättest Du diese "Eigenheiten" nicht. Der zusätzliche Warteaufruf (Timer) wird nur bei einer tatsächlichen Lock-Anforderung einmal aktiviert und ist dann wieder "still". Der (vollständige) Lock-Mechanismus ist unabhängig von der Anzahl möglicher Konkurrenten für jeden anfordernden Zug identisch und muss daher nur für jeden Zug dupliziert werden. Nur der zu setzende und zu überprüfende Lockwert, der den Lock-anfordernden Zug (oder das "Einfahr-Gleis" A bis C) identifiziert, muss für jeden einzelnen Zug (jedes einzelne Gleis) individuell und eindeutig sein.

Viele Grüße
BahnLand

Link to comment
Share on other sites

Hallo BahnLand,

Du hast natürlich Recht mit dem Denkfehler. Ich hatte ursprünglich ein anderes Verständnis vom dem Lock. So wie Du es beschreibst ist es aber natürlich richtig.

Nochmal zu dem Pürftakt:

Deine Annahme dass der Prüftakt immer läuft ist korrekt und er steuert nicht nur diese Weichen, sondern die gesamte Fahrwegssteuerung auf der Anlage.

Was die Algorithmus Anpassung betrifft, stimme ich Dir hingegen nicht ganz zu. Sicher, ich muss für jedes konkurrierende Gleis einen anderen Zählerwert prüfen und ja, ich muss im Prüftakt selber sicherstellen, dass er auch mindestens so viele Varianten durchläuft, wie ich konkurrierende Gleise habe. Damit hat es sich aber mit der Anpassung. Ansonsten ist die Implementation an jeder Stelle gleich. Das wäre aber bei Deiner Timer Lösung auch nicht anders. Hier muss jedes konkurrierende Gleis einen anderen Lockwert setzen. Dafür brauche ich dann so viele Lock-Timer, wie es zu verteilende Ressourcen gibt anstatt nur einen Timer bei meiner Lösung. Außerdem brauch ich für jede Variante mindestens zwei Ereitgnisse. Ein Ereignis, welches den Lock setzt und ein Ereignis, welches prüft ob man den Lock bekommen hat und bei Bedarf nochmal neu setzt. Bei meiner Prüftakt Variante reicht dagegen das "Takt" Ereignis aus.

Macht jetzt aber eigentlich keinen Sinn darüber zu streiten, welche Variante besser ist. Der Unterschied ist nicht groß und funktionieren tun sie beide.

Andreas

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...