Und eine Möglichkeit, das zu tun, ist nicht mehr zu beschreiben,
wie die Krypto-Struktur aussieht, indem man es hinmalt, sondern nimmt man indirekt das Ganze beschreibt.
Nämlich mit Prädikaten aus der Prädikatenlogik, also Prädikaten, erste Ordnung. Was wir als erstes haben,
ist eine Beschreibung der Zustandsmenge,
also eine Beschreibung von den Variablen in V. Also zum Beispiel,
wenn ich die Variantenmenge, wie im Beispiel angegeben 1,
V1 von 2 vor 3 habe, und ich möchte den Zustand repräsentieren,
dass die erste Variablenwerte 2 vor 2,
0W3 und V3, den wird 5 hat,
dann könnte ich das in diesem Fall direkt kodieren,
indem ich sage, das wird repräsentiert für die Formel V1,
gleich 2 und V2 gleich 3 und Bei gleich 5. Was brauche ich denn noch eine weitere Form dazustand beschreibt?
Was brauche ich dann noch? Dann muss ich das ganze
System selbst beschreiben. Ich muss also die Transitionen kodieren,
die die Variablen verändern können. Und dabei gehe ich davon aus,
dass die Variablen V nochmal existieren als Menge V-Strich,
wobei bedeuten soll, vor Strich ist die Variable Nachausführung einer Aktion.
Und wenn er die Transitionsrelation ist, dann bezeichnen wir mit Kalligrafie
eher mit den Argumenten V und V strich die Formel, diese Übergänge repräsentiert.
Also wichtig sind diese beiden Variablenmengen und die Relation.
Oder die Formel, die diese Relation kodiert. Wenn ich diese Kodierung ansetze,
dann kann ich eine Kripri-Struktur nochmal anders darstellen,
nämlich jetzt als Viertupel,
wo die Zustandsmenge mit der Formel für den Staatszustand S0,
der Formel Kalligraphie für die Übergänge und ES für die Belegung
Und das ist genauso, wie wir beschrieben haben, S,
das ist eine Menge von Belegung, S-0 ist die Menge.
Von Anfangszuständen, also Anfangsbelegung. Und natürlich möchte ich,
dass mein Prädikat, Kalligrafie eher für die Veränderung auf den Variablen vorn vorstrich,
das Gleiche ausdrückt, wie der Übergang von Zustand S-Zustustand S-Strich.
Und die Belegung ES kennen wir schon, das ist die Menge
der Formeln, die bei der Belegung S gelten sollen.
Also V ist Element dieser Menge EE-E-E-E-E-Index S von S,
genau dann, wenn Die Variable V unter dieser Belegung es wahr wird.
Schauen wir uns das mal für ein Beispiel an. Ein System mit zwei Variablen nur,
X und Y, der Wertemenge, 0-1,
das handelt sich also um binär Variablen,
was durchaus realistisch ist, denn oftmals wird Hardware damit verifiziert.
Das System ist beschrieben durch die Aktion X wird X plus Y,
Modulo 2, weil das Binärvariapien sind.
Und der Anfangszustand, in dem wir uns befinden,
ist X und Y
Ein solches System kann man beschreiben, indem man den Staatszustand,
er ist 0 von X und Y,
als das naheliegende Prädikat X gleich 1 und Y gleich 1 kodiert.
Und die Übergänge werden jetzt kodiert als X-Strich wird zu
X plus Y Modul 2 und Y-Strich ist gleich Y.
Denn die Variable Y verändert sich nicht. Deswegen ist Y-Strich
der alte Wert. Wenn ich diese Kodierung des Systems habe,
dann ist damit auch mal eine Kripke-Struktur geschrieben, Mit den Zuständen,
ich habe zwei Variablen, also D-O-2, D-Kreuz D.
Der Staatszustand S0 haben ja gesagt, das Pärchen 1-
1, weil beide Variablen mit dem Wert 1 starten.
Und jetzt habe ich Übergänge, die sind hier aufgeführt,
ein bisschen besser ist es, wenn man sie aufmalt,
dann sieht man, dass dieses System,
also vom Staatszustand 1-1,
den Zustand 0-1 erreichen kann.
Und dann gibt es isolierte Zustände,
1-0 und 0-0,
die nach Ausführung dieser Aktionen wieder der reichen Zustand sind,
also keine Veränderungen eintritt
Das heißt, bei einer solchen Kudium und der Krypto-Struktur
kodieren wir implizit auch immer nicht erreichbare Teile mit.
Meistens kodieren wir also nicht nur Binärvariablen,
sondern wir wollen auch ganze Programme kodieren.
Also typische sequenzielle Programme, was gehört dazu? Zumindest die
Klassiker. Eine Zuweisung gehört dazu in ein sequenzielles Programm.
Es ist praktisch, eine Anweisung zu haben, die nichts tut.
Also es gibt Hintereinanderausführung, klar, bedingte Anweisungen,
also ein If-Banels-Konstrukt und eine Schleife.
Das wäre schön,
wenn man das hat
Und ohne eine ganz, ganz tief in jedes Detail einsteigen zu wollen,
das kann man kodieren. Man kann es kodieren,
indem wir uns vorstellen, dass die Programme Zeilnummern anhaben.
Und jetzt gibt es die variable PC, Befehlszähler, Program-Counter.
Und das ist entweder irgendeine Zeile oder dieses Bottom-Symbol,
das beint, es ist gar nicht definiert.
Also das Programm ist gar nicht aktiv. Das heißt,
vor der Ausführung oder meistens ist das Programm terminiert,
wenn es auf dem letzten nicht weiterführenden Statement steht
Und im Prinzip ist das genau das, was man noch
von Debuggern kennt, die zeilenweise durch ein Programm durchlaufen.
Dann brauchen wir noch aus praktischen Gründen ein Prädigat Same auf
der Menge Y, die sagt einfach alle Variablen,
kleinen Y aus dieser Menge, bleiben unverändert.
Das heißt, Y-Strich ist Y. Und das soll natürlich eine Teilmenge von Variablen sein,
dieses Y. Dann kodieren wir auch immer noch PV.
Das ist die Anfangsbelegung der Variablen. Also was gilt vor
der Ausführung eines Kommandos
Und der Anfangszustand wird kodiert als initiale Belegung der Variablen.
Und Programmcounter steht auf der Startseilnummer, also typischerweise eins.
Oder in diesem Beispiel ganz kleines Programmfragment bestehend aus drei Zeilen,
in der ersten Zeile mit X,
der wird zweimal Y zugewiesen,
in der zweiten Zeile wird Y um eins erniedrigt.
In der dritten Zeile passiert gar nichts mehr,
also können wir davon ausgehen, da ist Termination.
Und der Anfangswert möge sein,
X gleich 1 und Y
Und wo wollen wir das Programm starten? Vermutlich in der Zeile,
in Line One. Und das kann ich codieren durch eine
sehr naheliegende Formel X gleich 1 und Y Recht 2 und PC gleich L1.
Damit ist also die Startkonfiguration vollständig beschrieben. Ich weiß also,
wie ich starte. Jetzt muss ich für jedes Statement,
das ich da habe, also in diesem Fall waren es zwei Zuweisungen,
muss ich jetzt irgendwie codieren, was ist der Effekt des Ganzen?
Der Effekt ist, irgendwelche Veränderungen der Variablen Werte,
einerseits und zweitens natürlich, Ich springe da irgendwie zu einer anderen Zeilennummer.
Also in diesem Fall möchte ich jakodieren, dass ich nach
der Ausführung der Zuweisung an X nochmal zur zweiten Zeile komme. Und um das auszudrücken,
gibt es jetzt ein weiteres Prädikat, die Prozedur C,
die drei Argumente hat, nämlich L und L Strich,
als Laien und Laien Strich, also wo ich starte,
die Zeilennummer vor der Ausführung und die Zahlennummer,
die nach der Ausführung der jeweiligen Anweisung
eingenommen wird
P ist das Programm selbst. Und natürlich ist es auch interessant,
wie sich die Programmcounter dabei verändern mit den Leinen anders.
Und das müssen wir jetzt durchexerzieren, und das können wir prinzipiell machen,
wenn wir das für alle Bestandteile wissen, und alle Operationen,
dann wissen wir für jedes Programm, wie sich da die Semantik verändern.
So, was wir jetzt im Folgenden machen,
wir definieren eigentlich nur das, was wir schon wissen,
also wie sich so einfache, imperative Programme verhalten.
Wenn man da die Zuweisung definieren will, also sagen,
was ist der Lieb, der Change,
Von L nach L. Strich, wenn ich die Zuweisung habe,
V bekommt den Wert einer Expression, eines Ausdrucks E.
Das ist noch sehr einfach, da sage ich,
ich starte in L., also PC ist gleich
L. Hinterher ist PC Strich, also die neue Zeile ist L-Strich.
Und V-Strich, der neue Wert von V, ist der Ausdruck E.
Und alle Variabien außer diesem V, die bleiben unverändert,
also same. Gut, das ist genau das,
was ich von einer Zuweisung erwarte.
Sie springen einfach zur nächsten Zeile
Das nächste, was man so klassischerweise hat, ist Hintereinanderausführung.
Also ich habe eine Location L und habe dann ein Programm
P1 mit L2-Strich, noch ein Programm P2 und L-Strich.
Und die Idee ist, dass man sagt, na gut,
da setze ich die Bedingungen zusammen von P1 ausführen und von
L nach L2-Strich zu kommen.
Also genau diese Zwischenlokalität. Und dann von L2-Strich mit
dem Kommando P2 nach L-Strich
zu kommen
Sodass oder es jetzt zwingend notwendig, in diesen Bestandteilen,
aus dem einfachen Grund, dass die Variablen ja alternativ betrachtet werden.
Das heißt, entweder ich bin ein L oder ich bin
ein L2. Beides geht nicht.
Würde ich also uns schreiben, würde ich fordern,
dass ich sowohl der Lokalität L auch L2 mühe.
Deswegen tut es unten nicht, aber oder bringt es.
Und das kann man sich grafisch so veranschaulichen,
wie man das erwartet.
Ich starte ein L mit P1
und hüpfe dann zur Lokalität
Um das Programm P2 auszuführen und rauskomme ich eben bei L-Strich.
Und diese Tatsachen werden rekursiv eben schon dadurch ausgedrückt,
dass ich weiß, was P1 macht und was P2 macht.
Hier nochmal der Hinweis, das ist ein Oder und nicht,
wie man erwarten würde. Was wir dennoch haben,
Schleifen anweisen und die brauchen wir auch unbedingt. Also ich will ausdrücken,
was ist der Effekt einer Wild-B-Du-P1-Schleife ist, wobei ich vorher starte,
in der Lokalität L der Schleifenkörper P1 hat die Lokalität L1,
damit ich sagen kann, da springe ich immer wieder hin.
Und nach der Schleife, das ist die Lokalität L1-Strich.
Und was gibt es jetzt an Komponenten da zu sagen?
Da gibt es mehrere Möglichkeiten, wenn ich mich gerade
bei L befinde, also PC gleich L ist.
Und die Bedingung B gilt. Dann bin ich hinterher
im Schleifenkörper und keine Variable hat sich verändert.
Ich habe also den Test ausgegeführt und er war positiv
Jetzt gibst du die Alternative. Ich starte an der
gleichen Stelle, aber B gilt nicht.
Also die Negation von B gilt. Ja, wo springe
ich dann hin? Ganz ans Ende in die Schleife.
Also ich komme zu L-Strich. Deswegen ist es PC-Strich gleich
L-Strich. Variablen verändern sich auch in diesem Fall nicht.
Also es ist sehr eben von V. Und dann ist die Aussage,
wenn ich in L1 gerade bin,
dann bin ich nach der Ausführung von P1 in L. Also auch,
wie man das erwartet.
Also genau so eine Weichenstellung wird hier kodiert
Wo ich am Anfang Testmuskel B oder die Negation von B
und dann bleibe ich entweder in dieser Schleife oder ich hüpfe gleich nach L-Strich.
Was fehlt denn noch? Skip ist sehr einfach.
Also wenn ich Skip ausführe, dann weiß ich,
vorher bin ich in der Linie L. Hinterher bin ich in
L-Strich und es hat sich nichts getan.
Alle Variablen unverändert. Gut, das ist genau das,
was ich hier von Skip erwarten.
Einmal ein Rüberhüpfen ohne Effekt. Und dann haben wir noch
die bedingte Anweisung. Die ist ja nichts weiter als Summe
Weiche. Also ich muss wieder testen, gilt B oder nicht B.
Und da gibt es auch die zwei Zeilen dafür. Die erste Zeile sagt,
angenommen, ich habe den oberen Fall, B gilt,
dann soll ja der Van-Teil mit der Lokalität L1 gewählt werden.
Und das drückt die erste Zeile aus, ich starte in L,
ich komme dann in den Zen-Teil mit L1.
Die Bedingung B gilt dazu und keine Variable hat sich verändert.
Alle bleiben unverändert. Oder der untere Zweig gilt, Das heißt,
ich starte in L kommen dann in den Els-Teil mit L2 als Lokalität,
weil die Bedingung B gerade nicht gilt.
Und durch diesen Test hat sich auch keine Variable verändert.
Oder ich habe den Test schon gemacht, bin also bei L1.
Ja gut, dann führe ich das Programm P1 aus mit
all seinen Effekten. Und kommen dann zu Els-Strich,
also dem Ausgang. Oder ich bin bei L2 gelandet,
im Els-Teil und lande dann auch hinterher bei Els-Strich.
So, wenn ich das brav alles durchexerziere und brav einsetze,
kriege ich für jedes Programm eine große Formel,
die alle Übergänge beschreibt
So, das ist erstmal für uns praktisch nicht ganz so wichtig,
was wir mitnehmen können, ist es erstmal die Tatsache,
dass zu jedem Programm wir so eine logische Darstellung finden.
Und das ist deswegen ganz praktisch,
weil im Hintergrund ein Werkzeug damit arbeiten soll,
das gerne wüsste, wie diese Mantik der Programmiersprache ist.
Und das Ganze dann auch gerne mit Formeln bearbeitet.
Hat komplexitätstheoretisch auch einen netten Effekt. Man muss nicht
die Kripke-Struktur kodieren, sondern nur eine Formel.
Und wer weiß, wie Wahrheitstafeln von Formeln wachsen.
Wir haben uns
eine Logik damit
Ja bestätigt, da weiß man, bei N-Variablen habe ich
zwei URM-Zeilen in meiner Wahrheitstafel. Deswegen ist es schon praktisch,
lieber mit der Formel zu arbeiten, als mit der gesamten Krypto-Struktur,
die jetzt alle im Simpson Fall 2 URN verschiedenen Zustände hält.
Gut, aber das muss eigentlich mehr das Werkzeug unter dem Programmierer eines Werkzeugs kümmern.
So, bislang ist es aber eigentlich noch recht einfach.
Natürlich sind auch sequenzielle Programme schon hinreichend komplex, zumindest wenn sie eine gewisse Größe haben.
Der andere Quell von Komplexität ist nicht nur die schiere Größe,
sondern die Interaktion, parallele Interaktion verschiedener Programmteile.
Das gibt es zwar im normalen Programmiersprachen so nicht,
bei Java mit Threads durch die Hintertür so rangeflanscht, durch die Hintertür.
Es gibt es aber in jedem Chip,
also in jedem Hardware-Chip läuft naturgegebenermaßen eine ganze Menge parallel.
Es gibt da irgendwie keinen sequenziellen Taktgeber, der da intern sitzt,
das ist nur die Illusion nach außen,
die ganzen vielen Teilprozessoren arbeiten logisch unabhängig und werden dann irgendwie synchronisiert an einigen Schallstellen.
Und um das auszudrücken, brauchen wir ein neues Konstrukt,
wir müssen also ausdrücken können dass wir parallel oder nebenläufig,
da wollen wir erstmal nicht unterscheiden,
Teilprogramme P1 bis PN haben und die Co.,
also nebenläufig zueinander, beginnen und beenden wollen.
Und die können sich auch irgendwie beeinflussen, dadurch, dass sie auf gemeinsame Variablen schreiben.
Also wir haben hier einen Shared-Memory-Model. Wir gehen davon aus,
dass im Prinzip die zwar irgendwie versetzt arbeiten,
also der eine mal der andere, Also eigentlich sowas,
was man auch als Skett-Uling hätte auf einen normalen Prozess oder dass irgendeiner rausgepickt wird,
die nächste Aktion auszuführen.
Und die Seitende Fett bekommen durch das Schreiben von gemeinsamen Variablen zustande.
Also gemeinsame Speicherbereiche. Und damit wir das wieder so ausdrücken können,
wie zuvor mit Zeilennummern das Ganze, wir sagen also,
wir haben Labels für jeden Prozess, also L1 und zu sagen,
wir treten ein in den einen Prozess und jeder Prozess PI
hat natürlich auch seine lokalen Liniennummern.
Und das gilt für jeden
der P1 bis PN-Prozesse wieder
Dann gibt es L1-Strich, als dieser Teilprozess es beendet,
dass ich rausspringen kann. Da die einzelnen Prozesse unabhängig voneinander sind,
haben wir jetzt nicht einen Befehlszähler, sondern für jeden Prozess einen eigenen.
Also einen globalen, wenn sie nicht verzweigen,
also dort, wo das Programm sequentiell arbeitet,
haben wir weiter PC als Variable.
Und sobald verzweigt wird durch ein solches Co-Beginn QN-Statement,
da brauchen wir dann eben
die Nebenläufigen,
verzweigten Befehlszähler PCI
Und die Startkonfiguration ist jetzt,
wir haben irgendwie eine Initialisierungsbedingung an die Variablen, Prä von V.
Der Programmcounter steht auf der initialen Zeile, hier M genannt.
Und die möglichen parallelen Operatoren, also PCI,
diese Line Numbers, sind alle undefiniert.
Sind also sämtlich am Anfang nicht aktiv.
Und wenn wir das repräsentieren wollen, ein solches Statement,
dann macht man das durch folgenden Ausdruck.
Dann sage ich, okay, was ist der Change?
In der ersten Zeile sage ich Initialisierungsbedingungen
Entweder ich stehe auf der ersten Zahl Nummer 11 und
alle lokalen Prozesse sind noch nicht gestartet,
stehen also auf dem ersten Zeilen L1,
was für den ersten Prozess gültig, LM für den Entenprozess.
Und PC-Strich ist undefiniert in diesem Fall. Oder ich bin
schon im Terminationsfall, also PC ist Bottom,
alle lokalen PCIs, PC1 bis PCN,
stehen auf den Endlinien,
L-Strich 1 bis 11 Strich
Terminationen merke ich dadurch, dass PC-Strich gleich L-Strich ist.
Und daran, dass alle Programmcounters,
die lokal in den Prozessen gelten, jetzt wieder undefiniert sind?
Oder dritter Fall, ich bin irgendwo dazwischen. Weil dann gilt irgendwie,
ich bin in L.I. gestartet und komme nach L.I. Strich,
wenn ich diesen Prozess P ausführe,
irgendeiner von denen macht jetzt eine Aktion,
die Variablen,
die V.I nicht hat,
bleiben unverändert
Also alle außer VI, VI sind die Variablen,
die ihr der Prozess hat.
Und auch die anderen Programmzähler verändern sich nicht. Es verändert
sich also nur PC. Wie sich das alles verändert,
ist ja in dem Change von L-I-P-I-I-Strich kodiert. Ja,
das heißt, dass der IT-Prozess eine Aktion ausführt als Ganzes.
Und was wir dann noch brauchen, ist,
wir wollen ja nicht nur mit Variablen kommunizieren,
sondern es gibt auch gewisse Synchronisationsbedingungen
Also typischerweise wollen zwei Prozessoren warten, dass irgendein Zustand erfüllt ist.
Dafür gibt es entweder in Prozessen oder im Assembler-Code oder
sonst wo ein Betriebssystem unterstützt, ein Away.
Also erwarte den Moment, an dem die Bedingung wahr wird,
warte, bis es begelt.
Das ist busy waiting im Zweifelsfall. Ja,
und so wird das hier auch beschrieben. Wir sagen,
der Change ist folgendermaßen, wenn wir bei L sind
Und die Bedingung B gilt nicht. Dann sind wir hinterher
immer noch bei L. Und die Variablen haben sich nicht verändert.
Ohne die Bedingung B gilt, also es ist das eingetreten,
was wir erhofft haben.
Ja, dann mache ich den Schritt von L nach im Strich.
Aber Variablen haben sich in diesem Fall auch nicht verändert.
Das heißt, es ist eine Seiteneffektfreie Operation.
Könnte man vielleicht auch so als Wien irgendeinen Weissleitkonstrukt ansehen,
solange B nicht gilt, bleibe ich in der Schleife drin.
Und erst wenn B gilt,
springe ich raus
Also was vielleicht wie, why are not be do skip?
Was wäre denn die Busy Waiting Variante? Wenn B also
falsch ist, bleibe ich da und in dem Moment,
wo es bar wird, springe ich ein weiter.
Und das brauchen wir,
um jetzt mal so ein Klassiker uns anzuschauen,
das weiß man aus alten Tagen der Betriebssysteme,
wenn nicht mehrere Prozesse laufen lassen kann und Uraltsysteme von Deck
und IBM konnten das schon sehr früh mit mehreren Prozessen arbeiten
Denn interessiert uns jetzt das Problem des wechselseitigen Ausschlusses.
Das ist also ein Programm, das aus zwei Prozessen,
P0 und P1 besteht, die parallel ausgeführt werden.
Und jetzt in einen kritischen Abschnitt gehen sollen oder eben nicht.
Und das immer bitteschön nur einer in diesen kritischen Abschnitt geht. Beispielsweise,
weil zwei Prozesse ein Wert an eine gemeinsame Stelle in der Datenbank schreiben sollen,
aber die sollen sich nicht ins Gehege kommen,
damit klar ist, welcher Wert gemeint ist.
Also solche Sachen braucht man, wenn Ressourcen gemeinsam genutzt werden und
ein verschränktes Schreiben Probleme machen würden, in Datenbanken oder Fallsystemen.
Auf Englisch heißt es wechselseitige Ausschluss Mutual Exclusion.
Und da muss man, schicke ich gleich vorweg,
wir betrachten hier nur den Fall, dass zwei Prozesse wechselseitigen Ausschluss begehren.
Für drei ist die Lösung, die man da machen könnte,
komplett anders. Typischerweise macht man das denn aber mit Hardware-Unterstützung.
Jetzt machen wir das erst mal so,
kann ich das überhaupt mit den Bordmitteln realisieren
Also im Deutschen, sagt man, beim wechselseitigen Ausschluss geht es darum,
einen kritischen Abschnitt, in den beide wollen, zu schützen.
Das heißt, es gibt einen Bereich,
der darf nicht überlappend ausgeführt werden, einen Programmbereich,
der wird exklusiv in einem ausgeführt oder vom anderen,
aber es ist nicht so,
dass beide so ein bisschen da in diesem Programm teil sind.
Im nicht kritischen Abschnitt kann ich das beliebig verschränken,
das macht gar keinen Unterschied.
So, und jetzt gehe ich davon aus,
ich habe zwei Prozesse,
P und
Und die sollen jetzt, damit das korrekt läuft,
zwei Dinge für mich erfüllen. Die erste Bedingung A ist,
sie sind nie gleichzeitig in ihrem kritischen Abschnitt, was heißt,
die Befehlszähler von P und Q befinden sich nicht in den Bereichen,
die ich als kritisch ansehe.
Die zweite Bedingung ist, wenn einer der beiden Prozesse,
nehmen wir mal an, das ist P,
den Wunsch verspürt in den kritischen Abschnitt zu gelangen,
dann kommt er nach einer irgendwie gearteten,
aber endlichen Zeit tatsächlich in seinen kritischen Abschnitt
Wenn ich nur die Bedingung A hätte,
dann wäre es einer. Leichtigkeit, das Symplementieren,
ich verbitte einfach beiden Prozessen in den kritischen Abschnitt zu gehen.
Damit wäre gewährleistet, dass nichts Schlimmes passiert.
Leider passiert überhaupt nichts. Es hat sich bewährt,
das aber so aufzuteilen und zu sagen,
ich habe hier zwei Eigenschaften im Englischen, heißen die Safety-Properties,
also Bedingungen vom Typ A sagen, es passiert nie etwas Schlimmes.
Also das Ganze bewegt sich in einem sicheren Rahmen.
Und das andere heißt Liveness Propertie, grob übersetzt, Lebendigkeit.
Also das tut auch mal was,
das Wünschenswerte tritt auch irgendwann mal ein. Im Deutschen,
es gilt immer, oder es gilt später irgendwann einmal,
das wären so die Umschreibungen im Deutschen.
So, wir müssen also, was wir gerne hätten,
wir hätten gerne kritischen Abschnitt für zwei Prozesse, P und Kuh meinetwegen.
Und jetzt fragen wir uns, wie können sowas aussehen?
Und jetzt gucken wir mal immer,
wie sieht das aus mit den Eigenschaften A und B
Das allgemeine Schema für ein solches Programm, ist das Folgende,
wir sagen, wir haben die parallele Ausführung von P und Q.
Also wir beginnen in M und sagen dort Kobegin,
P, parallel zu Kohl, Koent.
Und damit das nicht zu eng da wird,
sind die Prozesse P und Q da jeweils drunter dargestellt.
Die sehen absolut symmetrisch aus. Wir beginnen mit
einer Endlosschleife, Wild True Do.
Das machen beide
Und jetzt gibt es den ersten Bereich, das ist der nicht-kritische Abschnitt.
Beide führen ihn irgendwie aus, das kann über Lappen geschehen.
Dann gibt es irgendwie geschickten Code, der dafür sorgt,
dass nur einer von beiden jetzt in den kritischen Abschnitt kommt.
Also das Eintrittsprotokoll,
dann führt nur einer von beiden den kritischen Abschnitt aus,
verlässt die nach endlicher Zeit und räumt dann irgendwie auf.
Und das Aufräumen geschieht qua Austrittsprotokoll
Ja, und dann geht das Spielchen von vorne los.
Jetzt gibt es da verschiedene Lösungen, da könnte man sagen,
naja, es gibt auch sowas, eine Programmiersprache,
einige der moderneren haben so ein Monitorkonzept, da kann ich sagen,
dieser ganze Code-Bereich oder ein Jahr war halt mit Synchronize oder ähnlichen Scherzen,
kann nur von einem Aufruf aufgerufen werden.
Das Problem ist nur, ja, das ist ganz schön,
aber das ist die hochsprachliche Variante,
die sagt, das hätten wir gerne.
Das muss ja irgendwie nach unten abgegebildet werden. Da gibt es jetzt zwei Varianten,
Variante Nummer eins ist, man kriegt das in Software hin,
also wir können jetzt irgendwie das nachprogrammieren.
Das heißt, wir schreiben in die gelben Blöcke jetzt irgendwas.
Oder die Ingenieurslösung, wir lassen es die Hardware erledigen.
Wir können also irgendwie ein Spezialstatement ausführen,
das den Prozessor jetzt irgendwie mal nicht über Lappen blockieren kann.
Das klappt auf eine Ein-Prozessoren-Maschine, aber stellt euch vor,
wir würden das ausführen in ein Netzwerk.
P und Q sitzen auf zwei verschiedenen Rechnern und die
schicken sich eigentlich nur Nachrichten.
Und der gemeinsame Zugriff wird irgendwie simuliert
Da müsste ich, dass sie auch irgendwie mit Bordmitteln hinkriegen.
Denn es gibt ja keine wirkliche Hardware-Instanz,
die sagen könnte, jetzt schalte ich mal beide tot.
So, das habe ich nicht. Das kriege ich in asynchronen Netzwerken
auch so einfach nicht hin. Von daher ist es erstmal
gar nicht klar, ob diese Fragestellung überhaupt eine Lösung hat.
Das war auch relativ lange. Eine,
ich will nicht sagen offene Frage,
aber da haben sich ganz viele Leute,
die Zähne ausgebissen und viele Ansätze, die man hattet,
wann publiziert und dann leider aber nicht falsch.
Das hat dessen ein bisschen gedauert,
bis man etwas hatte,
was es tat
Und wir machen jetzt gewissermaßen im verkleinerten Maßstab den historischen Exkurs.
Wir gucken mal an, wie sich das entwickelt hat.
Und wir versuchen mal so den ersten Ansatz. Versuch Nummer
eins. Appellösung. Und die Idee ist, ja,
nicht kritischer Abschnitt, was da drin steht, ist eigentlich egal.
Das Eintrittsprotokoll ist folgendes. Ich sage so etwas,
ich habe die Ampelmetapher und ein Prozess sagt,
ich warte darauf, dass die Ampel auf grün steht.
Wenn sie auf grün steht, dass man im kritischen Abschnitt rein darf,
dann stelle ich sie schnell auf rot,
gehe in den kritischen Abschnitt, gehe wieder raus,
nehme sie wieder zurück auf grünstelle.
Das ist die Frage, tut es das?
Kann man mal nachvollziehen. Hier steht ein wechselseitiger Ausschluss 1,
wenn es das täte, müsste ich nicht eins drüber schreiben,
also es ist zu vermuten, es gibt ein Problem hier.
Nehmen wir mal an, der rechte Prozess geht zuerst durch den
nicht kritischen Abschnitt. Die Ampel ist im Moment auf Gehöhen,
in der ersten Zeile steht nämlich das Initialwert grün ist,
noch ist sie grün
Gut. Dann zieht der andere nach, die Ampel ist
immer noch grün, hat sich ja nichts verändert.
Deswegen kommen beide jetzt aus diesem Awade-Konstrukt raus.
Nehmen wir mal an, der linke schafft das zuerst.
Setzt die Ampel jetzt auf Rot, der Rechte zieht nach,
setzt sie auch auf Rot. Na gut, denkt man,
wenn sie beide auf Rot setzen, ist wohl nicht schlimm.
Naja, dann geht aber der Link in den kritischen Abschnitt,
weil er ja gesagt hat, ich habe freie Fahrt,
der Rechte macht das auch.
Das sieht nicht so richtig nach wechselseitigen Ausschluss aus
Also der erste naive Ansatz mit einer solchen Metapher,
der mir irgendwie einen Fleck einfach setzt.
Also was ist ein Ampel, Mbulien? Darf ich rein
, darf ich nicht rein? Das heißt zu sagen,
ich habe eine globale Variable und ich setze sie einfach auf,
ich will da jetzt rein, keiner soll sonst.
Das heißt, dann gucken darf ich, ist keiner drin,
reingehen und sagen, ich bin jetzt drin, genau das haben wir gemacht.
Auf grün warten und wenn man rein beruht setzen.
Da wir das nicht in einem Atemzug machen können,
wir haben also keinen, das wäre denn auf Semmel-Ebene,
Test and Lock. Manche Prozessoren haben so etwas,
da kann man eine Variable auf null testen.
Und wenn sie null ist, automatisch auf eins setzen und das atomar,
die Hardware garantiert nun ist. Wenn ich das hätte,
wird das hier klappen, nehmen wir ein gewissermaßen awade,
Ampel gleich grün und Ampel wird zu rot,
dann wäre das ein atomarer Befehl und dieses Problem können nicht auftreten.
In einem solchen sequenziellen Verarbeitungsmodell kann ich das aber
irgendwie nicht sicherstellen
Also gehen wir zum zweiten Versuch. Das sieht jetzt ziemlich
ähnlich aus. Nur, dass wir uns jetzt versuchen,
nicht mit einer Ampel zu machen,
sondern wir versuchen zu kodieren, will der andere Prozess.
Also wir haben zwei neue Variablen, One P und One Q.
Und hier sind beide am Anfang falsch. Also weder P will noch
Kuh. Jetzt gehen wir beide wieder in die Endlosschleife.
Und das Prozederes jetzt, die beiden Prozesse können beide Varianten lesen.
Und die Idee ist ungefähr folgende, naja,
wenn ich rein will, aber ich weiß,
der andere will nicht, dann gehe ich rein.
Ist ja auch eine gute Idee, mal gucken, was passiert.
Der erste Prozess P sagt, ich möchte in den kritischen Abschnitt.
Gut, der zweite will auch. Klar, Probleme gibt
es nur, wenn beide wollen. Jetzt steht hier,
ich bin so höflich und sage,
ich möchte nur dann den kritischen Abschnitt,
wenn der andere
gar nicht will
Das sagt der andere jetzt auch. Ja,
das war jetzt aber vielleicht ein bisschen zu höflich.
Wenn beide sagen, wir warten hier, dann bleibt er dort.
Und der andere bleibt auch dort. Und dann verklemmt sich
das Ganze. Das war also nett gedacht.
Er füllt also die eine Eigenschaft A schon mal.
Wir kommen nicht beide gleichzeitig einen kritischen Abschnitt. Leider kommen
wir beide nie in den kritischen Abschnitt für dieses Szenario.
Also Variante 2 ist da keine lebendige Variante.
Aber sicher
Variante 3. Wir sagen, naja, mit diesem,
was der andere will und ich nicht, ja,
das ist vielleicht gar nicht mal so schlecht.
Was sieht man jetzt hier für einen Trick?
Wir machen ein bisschen busy waiting. Also erstmal nicht kritisch
Abschnitt. Der andere zieht nach und jetzt gucken wir,
solange der andere noch will, also wenn der Prozess P feststellt,
das cool gerade will, dann sagt er,
okay,
ich ziehe das mal zurück
Und setze es wieder. Und der andere Prozess macht das genauso. Und je nachdem,
wie sich das so verhakt, also die Hoffnung ist,
dass ich jetzt One Pea auf falsch setze, das sieht jetzt der Prozess.
Kuh auf der anderen Seite stellt fest, Mensch,
der Prozess P will ja im Moment gar nicht rein,
stürzt also in den kritischen Abschnitt,
bevor der andere wieder auf True das Ganze setzen kann.
Ja,
und da One Kuh immer noch auf True ist,
bleibt der andere erstmal der Prozess P links in der Schleife
Das ist so die Grundidee. Durch dieses Aufbrechen,
er zieht einmal kurz zurück, P sagt, na,
ich ziehe zurück, setze das auf falsch.
Der andere hat die Chance, jetzt reinzukommen. Und danach sage ich
aber wieder, okay, irgendwann möchte ich auch mal.
Also setze ich das hinterher wieder auf True.
Was passiert da jetzt? Klingt ja erstmal nicht schlecht.
Also wir nehmen mal wieder an, beide wollen.
Der erste Prozess ist jetzt ganz nett und sagt, ich ziehe zurück.
Jetzt ist der zweite, aber dummerweise schon reingegangen,
sagt, also ich ziehe auch zurück
Dann sagt er, ich möchte wieder, der andere sagt,
ich auch. Und dann sind wir wieder am Anfang.
Und das Spielchen könnten wir jetzt im Prinzip nochmal treiben.
Das heißt, wir wiederholen dieses Bitte sehr nach ihnen.
Das heißt auch After You, After You Effect deswegen.
Oder Live-Log. Das bedeutet also, wir waren da zu
nett. Wir haben zwar dem anderen die Möglichkeit gegeben,
immer einzutreten. Also die Chance war immer da,
wenn sich aber beide symmetrisch wechselseitig die Chance geben,
dann haben wir
ein Problem
Ja, dann sagen wir beide, du darfst.
Nein, du darfst. Das Problem,
was wir hier sehen, liegt also daran,
dass die Prozesse, wie wir sie derzeit beschreiben,
völlig symmetrisch sind in dem, was sie tun.
Ja, das war bei den ersten drei Varianten so,
es war symmetrisch. Und ein Lösungsansatz könnte jetzt darum bestehen,
an dieser Symptri zu arbeiten, also eine Symmetriebrechung einzuführen,
eine Münze zu werfen oder so etwas.
Ja, jetzt wirft das Programm keine Münze,
ist ein bisschen anders
Und der Ansatz von Dikestar, Decker und Peterson,
die hatten im Wesentlichen die gleiche Idee, unabhängig voneinander entwickelt.
Und was wir jetzt präsentieren, ist gewissermaßen die Quintessenz davon.
Wir führen eine neue Variable Last ein, Werte 1,2,
2 wertig, die aber dann stelle ich fest,
ich habe hier drei Programmzähler,
PC und für jeden Prozess ein PC 0 und PC 1.
Die Varianten, auf denen die operieren,
sind alle gleich, also die globalen Variablen sind identisch mit
V0 und Vereins
Und die Variapien sind nur One P, One Cue und Lars.
Alle Variablen, die wir haben. So,
ein Programmcounter, Null, das ist der Spannende,
also wo befindet sich der linke Prozess?
Naja, entweder in der ersten, zweiten, dritten oder fünften Zeile.
Wir haben ja die vierte gestrichen. Und analog das für
den zweiten Prozess auch. So, der Anfangsprozess ist halt,
weil wir befinden uns an ihrer Initialisierungsstelle M,
die anderen haben noch gar nicht angefangen.
Ja, Gott, und unten dann die ganzen anderen Bedingungen
und das geht immer so weiter
Die Schleifenanweisung mache ich hier. Die Zuweisung, die beiden,
die Wade-Anweisung mit Busy-Wating, die Zuweisung da im Austrittsprotokoll.
Das kann man alles machen. Könnt ihr nachverifizieren, aber ich da
einen Tippfehler habe. Aber es ist eigentlich nicht so spannend,
denn ich weiß ja, was ich beschreiben will.
Den Zustandsraum nehme ich. Und ein so ein Osterei,
das hat jetzt fünf Komponenten,
die oberen beiden Zahlen sind immer die Programmzeile,
in der ich mich befinde.
Also der vorgerufene Zustand hat oben 1-
Weil sich beide Prozesse in der ersten Zeile befinden. Also dort,
wo sie sagen, ich möchte in meinen kritischen Abschnitt.
Und P mit True, da stehen die gerade.
Denn in der Mitte steht der Wert der Lars-Variable,
also eins oder zwei, wird in all diesen Eiern stehen.
Und dann gibt es noch True of Falls für die beiden Bond-Variable
. So, und da gibt es einen größeren Zustandsraum.
Und was wir jetzt sicherstellen müssen, ist,
dass auf allen diesen halt die Eigenschaften A und B gelten.
So, wie habe ich dieses Zustandsdiagramm zu lesen
Am Anfang weiß sie ja, bin ich im Zustand leihen.
P1 und Q1. Last ist gleich 1, das ist der Initialisierungswert.
Kann aber auch zwei sein, das ist nicht wichtig.
Deswegen habe ich hier zwei Startzustände zur Auswahl.
Also es gibt nicht festgelegt, verschiedene Runs dieses Systems,
weil der Staatszustand nicht deterministisch gesetzt würde. Wenn man was erwarte ich jetzt,
wenn ich diese Anweisung OneP gleich zu ausführe,
ich erwarte, dass ich dann in den Zustand komme,
wo ich in der Zeile P2 bin,
und da sieht man hervorgehoben, Zustand 2, also P2 habe ich.
Und der andere hat sich nicht verändert,
bleibt also auf Q1. Lars hat sich nicht verändert.
Aber natürlich ist jetzt die erste Komponente True geworden.
Genau dieser Effekt auf One P von Falls of True.
Da muss ich mal nachgucken, die Lars-Variable wird verändert,
wird nämlich auf eins gesetzt. Naja,
wenn sie jetzt schon eins ist, dann passiert da eigentlich nicht so viel,
außer dass ich jetzt einen Befehl abgearbeitet habe,
bin also jetzt eine Zeile Nummer 3 gelandet, die Variable,
ansonsten haben sich nicht verändert.
Und jetzt kommt die Awade-Bedingung, will der andere nicht
Ja. One Q ist Falls, also darf ich da
durchhüpfen? Kommen also durch meinen kritischen Abschnitt gerade durch,
bin also in der fünften Zeile und in der fünften Zeile,
setze ich One Pee wieder auf Falls und springe zurück.
Bin also wieder da oben. Das wäre so ein Ablauf,
bei dem nur der linke Prozess irgendwas getan hat.
Ein Ablauf. Jetzt können wir gucken,
wie sieht das mit einem anderen Prozess aus,
wenn Lars zufällig zwei ist
Naja, ähnlich, sage ich mal. Auch dort setze ich wieder
den Eintrittswunsch auf True. Da ist das Gleiche in Grün,
nur dass die Variable Lars jetzt 2 in der Mitte ist.
Direkt daneben. In diesem Fall gucke ich wieder nach,
wie sieht das aus? Lars gleich 1, naja,
verändert den Wert. Und jetzt habe ich den gleichen Zustand
wie eben, ich habe ja Last of 1 gesetzt.
Beim ersten Mal war es schon eins und wird auf eins gesetzt,
ja, das habe ich es von 2 auf 1 gesetzt.
Kommen also im gleichen Zustand. Kommen also nicht überraschend da
auch wieder genauso durch
Jetzt können wir mal was anderes gucken. Können wir den
anderen Prozessen einen Schritt machen lassen? Also der zweite Prozess
fängt mal an. Und jetzt zieht der erste Prozess nach.
Die sind also jetzt beide in der zweiten Zeile.
Und das führt dazu, wo bin ich jetzt?
Kommt die Variable Lars dran? Die habe ich
jetzt auf eins gesetzt. Bin ich mal da,
bin ich im mittleren Bereich
Jetzt habe ich mal eine Situation,
wo beide Prozesse in den kritischen Abschnitten wollen.
Also TTs steht da unten. Beide sind wahr.
Der letzte war Nummer eins. Und was ist jetzt der
Fall? One cue falls. Nee, geht nicht.
Lars gleich zwei gilt auch nicht. Was passiert also?
Ich mache Busy Waiting. Ich bleibe in dem Zustand.
Und das ist im Prinzip so lange,
bis der andere Prozess sich mal rührt
Die einzige Möglichkeit, hier rauszukommen, ist, ja,
dass der andere Prozess den Schritt vom Zustand Q2 auf Q3
macht und nach unten weggeht,
wodurch sich denn auch die Last-Mariable ändern wird.
Die wird dann auf zwei gesetzt. Und dann sieht man,
dann kann der erste Prozess in den kritischen Abschnitt. So,
wenn man jetzt nochmal guckt, wie war das jetzt eigentlich,
wir haben uns jetzt wieder ein paar Beispiele nur angeguckt,
einfach nur mal mit dem Transitionssystem bewarnt zu werden.
Wie sieht das aus bei diesen beiden Prozessen?
P und Q wollte ich ja folgende Eigenschaften realisieren,
Eigenschafte, aber sie sind nie gleichzeitig im kritischen Abschnitt
Und wenn einer will, dann darf er auch Eigenschaft beten.
Also Safety und Lifeness. Und jetzt kommen wir zu diesem Zustandsraum
wieder zurückkehren und fragen, gilt die Eigenschaft A in diesem Zustandsdiagramm?
Woran kann man das sehen,
dass die Eigenschaft gilt oder woran könnte ich sehen,
dass sie verletzt wird
Und wir beide Aspekte machen. Das heißt, das erste,
was es arbeitet, wird zu uns sein.
Dann habe ich noch nicht begriffen, wenn beide irgendwie eine Kante haben.
Ja. Ja, das wäre ein Problem,
aber die Eigenschaft A sagt ja,
sie sollen nicht beide im kritischen Abschnitt sein und ich habe
noch nicht gesehen,
was das damit zu tun hat
Das ist gar nichts. Ja,
also uns interessiert eigentlich der Zustand, wo wir sehen würden,
also der eine Prozess ist ein P4 und der andere Prozess ist ein Q4.
Die habe ich jetzt nun gerade gestrichen, also muss ich mir das analog überlegen.
In P5 und Q5. Ja, das interessiert mich.
Gibt es einen Zustand, in dem P5 und Q5 gilt,
wenn das der Fall wäre, dann hätte ich ja einen Fehler.
Also muss ich überprüfen, dass nicht P5 und Q5 gilt.
Also das ist kein Osterei mit 5, 5 gibt.
In diesem Diagramm. So, und das kriege ich relativ schnell hin, relativ.
Also ich gucke mir jetzt jedem Knoten brav an.
Irgendwie ein Grabsuch-Algorithmus werfe ich jetzt an, der sagt,
ich eier jetzt brav alle Knoten durch.
Wenn das da schon so angemalt ist, machen wir nochmal Breitensuche.
Das ist für Menschen so einfach, so zeilenweise.
In der ersten Zweile 11. Ja, da steht dann 21 und 12,
dann steht da 31, 22, 22, 13. Ja,
dann 51, 32,
23,
Dann kommt 52, 33, 33, 25,
53, 35. Nee, 55 ist nicht dabei.
5, 5. So, diese Eigenschaft, das geht noch
ganz zügig. Jetzt kommt die nächste Eigenschaft. Wir fragen
uns, gilt B? B war ja die Eigenschaft,
wenn einer will, dann darf er auch.
Wie könnte ich das
jetzt ausdrücken
Tschüss. Also ich muss eigentlich so etwas realisieren können,
wie ich gucke mir jetzt einen Zustand raus,
sobald da ein Schuh drin vorkommt, Muss ich jetzt anfangen zu gucken,
ob es davon in der Zukunft,
also einen Kantenzug erreichbar, jetzt einen weiteren Knoten gibt?
Also nehmen wir mal an, es ist One Pea,
da muss ich ja irgendwie in den kritischen Abschnitt kommen.
So, das heißt, ich muss sagen,
wenn ich will, dann muss ich irgendwann mal nach P5 kommen.
In der Zukunft gibt es also erreichbar einen Knoten,
denn die Eigenschaft hat, es steht eine Fünf drin.
Also ich müsste jetzt immer gucken, aha,
wenn ich mal gewollt habe für irgendeinen Truh,
also in der zweiten Zeile, da stehen ja eine ganze Menge Truhs,
kann ich da immer zu einem Knoten kommen,
deren Fünferknoten ist
Gut, wenn ich angucke, welche Fünferknoten es gibt,
dann gibt es da gar nicht so viel zur Auswahl.
Das sind die, die da ganz unten außen sind,
also einmal im Halbkreis versammelt. Ich muss jetzt also überprüfen,
ob zu jedem True-Knoten ein Pfad dorthin wieder führt.
Gut, das ist vielleicht noch ein bisschen holperig formuliert.
Das ist irgendwie nicht ganz so elegant. Im Zustandsraum
jetzt und irgendwie bei Kantenzügen und Knoten zu argumentieren.
Also versuchen wir das nochmal. Wenn wir uns das fragen,
Die Bedingung B gilt, dann wäre es schöner,
dass irgendwie durch ein Spezialkonstrukt auf der Logikebene auszudrücken.
Für A konnten wir sagen, nicht P5 und Q5,
also nicht beide gleichzeitig. Ich habe aber ein Aussagenologie,
kein Konstrukt, das mir sagt, wenn jetzt,
meinetwegen One peagelt, also ich meinetwegen in Zeile P1 bin,
dass ich dann irgendwann auch mal nach P5 komme.
Dieses irgendwann kann ich
nichts sagen
Denn wenn ich das so betrachte, dann gilt ja,
dass immer für einen aktuellen Zustand, also P5 und Q5,
beziehen sich immer auf den gleichen Zustand, wenn ich das frage.
So, also ich müsste mir ein neues Wort oder ein
neues Zeichen für irgendwann einmal ausdenken.
Na gut. Tu. Dafür nehme ich diese Laute in
Salmi. Und ich sage, wenn jetzt P1 gilt,
dann impliziert das, dass später einmal oder irgendwann einmal P5 gilt.
Das ist das neue Konstrukt
Kommen wir nicht jetzt irgendwo starte? Dann heißt das zum Beispiel,
wenn ich da oben wollte, auf diesem Pfad, naja,
dann komme ich zu dem Zustand der 5-1,
also ich darf dann irgendwann mal aus.
Oder wenn ich dort rechts starte,
in einer anderen Startkonfiguration, gelingt es mir auch,
nach einem etwas längeren Pfad auch einen Knoten,
der mit fünf beschriftet ist,
mit P5
zu erreichen
Das sind jetzt so verschiedene Varianten. Wenn ich jetzt hier starte,
aus der anderen Perspektive,
die hier und da in der Schleife bleibe,
wer ist denn gewährleistet, dass ich da irgendwann mal rauskomme?
Das ist ja auch irgendwie eine mögliche Ausführung. Ja,
es könnte ja sein, ich habe ja busy waiting implementiert für wait.
Und jetzt befinde ich mich in P3 und Q2 und P3
ist ja die wait-Anweisung und der
testet immer
Ob diese logische Bedingung da gilt und stellt jedes Mal fest,
nein, sie gilt nicht, nein, sie gilt nicht,
nein, sie gilt nicht, nein, sie gilt nicht.
Die einzige Chance, da wieder rauszukommen, ist,
dass der zweite Prozess Kühmall zum Zuge kommt.
Nur ist das gewährleistet? Mathematisch haben wir das irgendwie nirgendwo
kodiert, fixiert, sozusagen, dass das ausgeschlossen wäre.
Es ist ja nur gesagt, irgendwelche Abläufe,
also wir haben bislang noch nicht gar nichts gesagt.
Das heißt, wir betrachten alle möglichen Abläufe und ein möglicher Ablauf
ist, der andere Prozess kommt irgendwann nie mehr dran
So, dann hätten wir tatsächlich ein Problem.
Da wird die Eigenschaft ja nicht gelten,
weil jetzt sehen wir einen Pfad,
der endet dort in diesem Zustand S11 und bleibt dort für alle Ewigkeit,
kommt also nie in den Zustand.
Ich habe den kritischen Abschnitt mit P5 verlassen. So,
in diesem Sinne würde das Ganze also nicht gelten.
Nun ist es aber so, das ist ja auch
anschaulich gesehen schon eine höchst unrealistische Situation.
Wenn ich einen Schedule habe, der sich ab einem gewissen Zeitpunkt entscheidet,
den anderen mal verhungern zu lassen.
Also sagt man sich, naja,
das will ich ja doch mal ausschließen können
Und das heißt dann ein bisschen Vornehmer,
dass das Ganze eine verschleppungsfreie Schaltregel sein soll.
Wenn einer kann und der Prozess Kuh kann ja,
dann kommt er vielleicht nicht ständig dran,
aber es ist nicht so, wenn er jetzt kann,
dass er nie mehr dran kommt.
Also ein Prozess, der noch was tun kann,
kommt auch mal irgendwann dran. Also darf nicht verschleppt werden,
man darf die nicht verhungern lassen. Sodass man jetzt auch an.
Das ist für eine nette Eigenschaft für einen solchen Prozess.
Man wird also sagen, Ablauf wäre zwar problematisch,
aber ich kann ihn aufgrund von mehr oder weniger physikalischen Grundannahmen ausschließen.
Wenn ich das als Grundannahme reinstecken darf, dann gibt es
diesen Ablauf gar nicht. Ja, das ist kein Ablauf,
den das System real zeigen kann. Das ist mal die Frage natürlich,
für welche Systeme betrachte ich das,
wenn das ein nebenläufiges System mit Ausfall ist,
wo der zweite Prozess ausfallen kann,
dann ist das vielleicht gar nicht mal so unrealistisch,
dass ich diesen Pfad einnehme.
Aber wenn ich einen Prozessor habe und einen Skedular,
der das nicht realisiert, Also wir wissen, was wir tun wollen.
Wir wissen auch im Prinzip, wie wir es rauskriegen.
Wir wissen eigentlich aber noch nicht, was wir da
gerade gemacht haben, als wir diesen Salmy eingeführt haben.
Wir haben nämlich eine neue Logik erfunden. Wir haben eine
Logik erfunden, temporale Logik oder Temporallogik. Eine Logik,
also die über Aussagen über den zeitlichen Ablauf von Systemen
besprechen kann. Und was uns genauer eigentlich interessiert,
also eigentlich wollen wir nicht wissen,
ob jetzt nicht P5 und K5 gilt, sondern eigentlich wollen wir wissen,
da haben wir jetzt noch einen neuen Operator dafür,
dass es in allen möglichen Abläufen nicht gibt.
Jetzt, wenn ich ein Quadrat davor male, habe ich ja wieder einen neuen Ausdrucksoperator.
Und der soll jetzt bedeuten, dass das für alle möglichen Systemabläufe gilt.
Immer gilt das. Das heißt, eine Temporallogik kann ich,
die wünschenswerte Eigenschaft ausdrücken als immer gilt, also in jedem Zustand,
den ich mal unterwegs so hätte erreichen können,
gilt die Eigenschaft nicht, P5 und Q5.
Und immer, das heißt, jeden Zustand,
den ich mal so einnehmen kann, Wenn in diesem irgendwie zukunftsorientierten Zustand P1 gilt,
dann gilt, dass irgendein Folgezustand dann P5 erfüllt.
Also irgendein Folgezustand, vielleicht sogar der Zustand selbst,
aber nach endlicher Zeit. Gut, wenn das solche Eigenschaften sind,
die man für Systeme mit zeitlichem Ablauf spezifizieren möchte,
wenn ich da solche Operatoren ganz praktisch finde,
dann bin ich jetzt bei temporaler Logik.
Und temporale Logik ist deswegen ganz attraktiv,
weil sie Mehr kann als Aussagenlogik, haben da gesehen.
Das ist ein Spezialfall der sogenannten Modallogik. Aber das Nette ist,
bei Predikatenlogik müssen wir gleich,
da kommen wir in Unentscheidbarkeitsprobleme und Dinge zu entscheiden,
ob Formeln der Predikatenlogik da gelten, das ist gar nicht mal so einfach.
Wir werden sehen bei Modallogik ist das ganz nett.
Wenn ich das in Predikatenlogik ausdrücken wollte, dann würde ich das auch machen können.
Ich würde es dann aber indirekt einführen im Prädikatenlogik,
würde ich sagen, eine Eigenschaft P ist gültig zum Zeitpunkt T.
Dann würde ich sagen, sowas vielleicht wie, es gibt
einen Zeitpunkt T, an dem die Eigenschaft P Geld.
Mit solchen Hilfsmitteln, also dem Quantoren und der Eigenschaft,
dass sich dann Prädikate mit einem expliziten Zeitparameter versehe,
habe ich die Möglichkeit, das natürlich rein zu kodieren,
aber es ist vielleicht A nicht so direkt B,
man hat immer noch viel zu viel in der Prädikatenlogik,
um das Ganze, macht das vielleicht ein bisschen aufwendiger.
Und Temporallogik bietet dort den eleganten Ausweg, dass es algorithmisch effizienter liegt. So,
da kann man jetzt mal schauen, welche Literatur kann man da zugrunde legen,
sondern von einem der Erfinder, sagen wir mal, das Model-Checking,
Herrn Klark und Kollegen, gibt es das Buch Model-Checking,
also mit einem starken Fokus auf Hardware-Verifikation.
Das zweite und französische
Buch auch
Was man dann findet bei diesen drei, also im ersten Girofalk.
Dort gibt es unter der Petrinetz-Perspektive einen dritten Abschnitt,
in dem es speziell um Model-Checking, als Verifikationstechnik geht.
Ein sehr schönes Buch, um Logik, auch Modallogik,
aber auch nochmal eine Wiederholung von Aussagen, Prädikatenlogik ist Hooth a Ryan,
den haben wir schon kennengelernt mit der abstürzenden, explodierenden Ariane 5.
Und ein sehr neues Buch von 2008,
Bayer und Cartoon, Princess of Model-Checking,
auch ein
sehr dickes Buch
Also wenn man es mal nachlesen will, was über diesen Stoff der Vorlesungen ausgeht.
Der ist bestimmt mit dem letzten Werk mehr als ausgelassen.
Und nochmal den Bezug zur Prädikatenlogik zu machen,
wenn kann man jetzt nicht überlegen, was spezifiziert man,
vielleicht einen Aufzug fragmentarisch.
Oder könntest du verschiedene Eigenschaften geben, die einen interessieren,
zum Beispiel, wenn ich auf den Knopf drücke,
also einen Aufzug anfordere,
dann wird das irgendwann mal auch bedient.
Und der Aufzug passiert kein Stockwerk
Wo es noch eine Wartende, also eine nicht erfüllte Anforderung gibt.
Also er lässt keinen aus. Man kann sich bestimmt Fahrstühle
mit Priorisierung von wichtigen Drückern ausdenken, aber der ist es nicht.
Und da ist das gute alte Beschleunigungsgesetz, also Dinge fallen nach unten,
Minuszeichen und sie tun es mit der Erdbeschleunigung, um das quadratisch zurzeit.
Wie spezifiziere ich das Ganze jetzt? Naja, es ist
ein relativ länglicher Ausdruck. Jede Anforderung mit erfüllt,
also wenn ich Ein Zeitpunkt T habe einen beliebigen,
also für alle Zeitpunkte T. Und ich habe eine Anforderung im Stockwerk N.
Zum Zeitpunkt T, dass ich gern einen Aufzug hätte.
Dann gilt, das ist ein Zeitpunkt T-Strich gibt,
der in der Zukunft liegt, also echt größer ist als T.
Und zu diesem Zeitpunkt T-Strich bedient der Fahrstuhl
auch das Stockwerk enden
So, also wenn eine Anforderung da ist,
gibt es eine Zukunft, in der bedient wird.
So, die zweite Bedingung ist auch nicht gerade kurz,
aber man könnte es machen. Also er lässt nichts aus.
Wenn ich also zwei Zeitpunkte T&T-Strich habe, wobei T-Strich größer als Tee ist,
dann gilt für alle Anforderungen am Stockwerk N, also für alle Stockwerke.
Wenn ich eine Anforderung in N habe, zum Zeitpunkt T,
Und die Position des Fahrstuhls zum Zeitpunkt T-Strich,
also dem zukünftigen, ist nicht dieser Stock M.
Dann gibt es noch einen Zeitpunkt T-Travel. Der liegt irgendwie
zwischen Tee und T-Strich. Und wenn dann gilt,
dass ich an diesem Zeitpunkt im Stockwerk N bin,
dann gibt es sogar einen Zeitpunkt T-Surf,
also einen Bedienungszeitpunkt,
der auch in diesem Intervall liegt und zu diesem Zeitpunkt
wird das Stockwerk N bedient
So, was lernen wir daraus? Man könnte das
so machen, aber man will das nicht so machen.
Ja, das ist ein bisschen länglich. Der Zeitpunkt T,
wenn man mal guckt, der kommt eigentlich überall vor.
Und dadurch, dass der Zeitpunkt T eigentlich in allen Prädikaten
hier eine Rolle spielen, ist alles zeitabhängig.
Das ist ein gutes Indiz, dass man das irgendwie noch eleganter hinkriegt.
Wenn ich weiß, jedes Prädikat hat sowieso einen impliziten Zeitparameter,
dann kann ich den ja irgendwie in die Logik selbst und der Bedeutung reinverbannen.
Und das ist genau die Idee von Zeitlogik.
Es gibt verschiedene Zeitlogiken und eine Zeitlogik ist älteste,
ist linear time logic. Erfunden von meiner Armir Pnoeli,
1977, LTL, Linia Time Logic.
Und das andere, der Gegensatz dazu ist CTL von Clark,
eben jedem Herrn, der in der Buchempfehlung auch vorkam.
Und zu beiden Logiken gibt es dann noch eine Oberlogik,
die werden wir uns auch mal ganz kurz ansehen,
aber nur am Rande behandeln,
sogenannte CTL-Sternlogik
Dass die CTL steht für Computation, Tree Logic von Amazon
und Halpern, das sind Co-Autoren des Modelchecking-Boosts.
Wir wollen uns im Wesentlichen hier LTL und CTL anschauen und beginnen mit LTL.
Und LTL interpretiert Zeit als diskrete Zeit. Wir haben also
diskrete Zeitpunkte, T0, T1, T2 und so weiter.
Also schon mal keine Modellierung von Zeit als reellwertiger Größe
Ist ganz klar,
wenn ich das als natürliche oder als ganz zahlige Werte annehme,
die Zeitpunkte, dann wird das einfacher werden,
als wenn ich reellwertige Zeit annehme.
Und was ich dann mache, ich picke mir eine mögliche
zeitliche Entwicklung des Systems raus. Also habe ich einen Zeitstrahl,
also einen Durchlauf des Systems und weiß dann zu jedem Zeitpunkt,
welche Eigenschaften gelten.
Und die Zentrale, Ausdruckmöglichkeit ist ja Raute P,
besprochen als irgendwann einmal gilt P. Also grafisch
Gelb, hervorgehoben. Es gibt so einen Zeitpunkt TN und ich bin mir sicher,
dort gilt die Eigenschaft P. TN könnte auch T0 sein.
Wäre auch möglich. Jetzt ist auch in der Zukunft.
Und von jetzt an gilt immer P. Das ist ein bisschen
eindeutiger. Das muss jetzt für alle Ewigkeit gelten.
Also von hier an gilt jetzt immer,
dass P gilt
Und das Nette ist, das sind Operatoren,
also irgendwann einmal und von jetzt an immer.
Auch gesprochen als Raute und Box. Die kann man natürlich
auch kombinieren. So wie meine Formeln beliebig kombinieren kann,
also diese Raute und diese Box müssen nicht am Anfang stehen.
Die kann ich auch schachteln. Ich kann also
solche Ausdrücke schreiben, wie irgendwann gilt immer P.
Was bedeutet das denn? Ja, es bedeutet irgendwann einmal
, vielleicht da,
Und ab da fehlt es immer. Und das kann ich
auch umdrehen. Ich kann sagen, immer gilt irgendwann einmal P.
Was bedeutet das denn? Wenn immer gilt, dass es
irgendwann mal gilt. Ne, also jetzt gilt immer,
gibt es einen zukünftigen Zeitpunkt offensichtlich in dem P gilt
Hat, dass man auch mal ein bisschen Zeit hat.
Ja, ist richtig, aber man kann es noch ein
bisschen mehr aussagen. Also wenn es einmal gegolten hat,
dann gilt es trotzdem später wieder mal. Habe ich das
verstanden? Und da muss es ja nur einmal gelten.
Also irgendwann einmal P heißt einmal in der Zukunft.
Wenn das immer da steht, dann muss das
irgendwie kräftiger werden,
diese Eigenschaft
Ja. Kann man das vielleicht noch griffiger umformulieren?
Ja, also unendlich oft muss es gelten. Denn egal,
wo ich hinspringe, in welcher Zukunft auch immer,
da gibt es ja noch davon wieder erreichbare Zukunft,
wo es gilt.
Und das egal, wo ich bin. Ja, immer
wieder kommt das vor. Das heißt, es kommt hiervor
da. Da gibt es da wieder eine Zukunft von und
immer so weiter.
Also an verschiedensten Stellen
So, jetzt kommen wir zur Syntax dieser Formeln.
Da müssen wir also wieder mal definieren, was sind überhaupt
die syntaktischen Ausdrücke, mit denen wir umgehen wollen?
Und dann gibt es schon mal zwei Schreibweisen,
was schlichtweg daran liegt, es gab zwei Schulen und je nachdem,
wer man so angehört.
Einige schreiben Boxp und andere schreiben für G. P dafür.
Geh als Abkürzung für Globaly. Also immer. Und während
die einen Raute P schreiben, schreiben die anderen FP
für Future
Ja, was hat das für einen Vorteil? G- und
FCNSG-Zeichen. Ja, also das ist der primäre Vorteil.
Beim Tool kann man das leichter eintippen, sag ich mal. So,
und ansonsten, Leute, die von der Richtung Modallogik her kommen,
für die ist Box und Raute schon das gewesen,
was es immer gab.
Und für die anderen, die nehmen eben G und S.
So, wir verwenden jetzt beides Mund austauschbar.
Box oder G, Raut oder F. Könnt ihr mal auch was aussuchen.
Ich versuche möglichst pro Formel nicht zu mischen, aber Selbst wenn.
So, was gibt es dann noch? Also das gibt
dann so muntere Ausdrücke wie Geh von P oder Nicht-Kuh.
So, und dann gibt es noch einen neuen Apparator.
Den hatten wir bislang noch gar nicht.
Den lesen wir als Antil. Das heißt,
die fördere Bedingung P oder Nicht-Kuh gilt an Till,
also Englisch, solange bis das dahinter gilt.
Also XP und X ist die Abkürzung für Next.
Also der direkte Nachfolger
Oder nicht cool, gilt also so lange,
bis im einen weiter, in der Zukunft pegelt.
Ja, mindestens so lange, vielleicht auch noch länger.
Aber mindestens so lange, bis irgendwann mal im übernächsten Schritt pegeln.
Und es gilt in der Zukunft irgendwann mal er.
Also solche Ausdrücke kann ich machen. Ja,
und damit das nicht durcheinander kommt, sind Formeln oder
atomare Ausdrücke mal klein geschrieben und die Operatoren Großbuchstaben.
Und davon haben wir auch nur G-U-X und
Und das Ganze kann man dann auch in eine Definition packen.
Ich gehe davon aus, ich habe eine Menge von Aussagen,
logischen Atomen, also kleinstmögliche Formeln, das ist die Menge AP.
Und die Syntax von LTL-Formeln kann ich jetzt in Bakus-Nauer-Grammatik ausdrücken,
indem ich sage,
eine Formel ist entweder die konstante True oder False oder eine atomare Proposition P.
Und wenn ich schon Formeln habe,
dann ist nicht F eine F und FF oder F,
XF,
Lobby our generally F-Antel F. Also diese Operatoren haben wir.
Wobei X halt der nächste Zustand ist, Future und Globaly,
die haben alle ein Argument, eine Formel.
Und Antil hat eben zwei. Das kann man dann hier
auch ein bisschen weniger klammern, schreiben natürlich,
also nicht, hat typischerweise keine Klammerung.
Und X soll relativ stark binden,
deswegen XP, kann auch ohne Klammern auskommen
Und ein Operator WG und F, wenn da nur ein
Atom hintersteht, dann klammern wir da auch nicht mehr.
Also Atome werden nicht geklammert. So,
jetzt die LTL-Operatoren, gibt es Paar von,
also X für Next Time P gilt im zweiten Element.
A1 der Folge, also ich gehe davon aus,
dass ich Folgen habe an 0A1, A2 und so weiter.
Und ich interpretiere immer ab dem Zeitpunkt T gleich 0.
Das heißt, das zweite Element der Folge ist jetzt
Und da soll jetzt die Form mit P gelten.
Alternative Schreibweise statt X ist Kringel-P, Kreis-P. FP eventually in the Future,
P gilt irgendwann in einem folgenden Element der Folge.
Wissen wir, können wir auch als Raute-P schreiben.
GP always a globally gilt in allen Elementen der Folge ab jetzt.
Auch BoxP geschrieben. Und einer fehlt noch an Till.
Das bedeutet formal, es gibt ein Element der Folge,
Ja, da gilt Kuh. Und davor gilt immer P.
Also wenn ich so einen Zeitstrahl habe, in einem Ablauf,
dann gibt es hier diesen einen Moment, an dem Kuh gelten muss.
Und das ist garantiert. Irgendwann gilt tatsächlich mal Kuh.
Und davor ist einmal komplett durchgearbeitet. Hier schön im Gelb
, da gilt immer P. Also überall echt davor.
Wenn Kuh gilt, dann muss P nicht mehr gehen.
Ja, aber dieses Antil stellt implizit auch sicher,
dass irgendwann mal Kuh gilt
Können wir uns mal ein Beispiel antun, hier mit schönen Bund.
Also es gibt so verschiedene Sachen, es gibt runde Dinge
und bunte Sachen und eckige Sachen und spitze Sachen.
Und dann kann ich sagen, in der Zukunft gibt es einen Zeitpunkt,
das kann ab jetzt sein oder irgendwann mal,
da gilt nicht rund an Till Roth.
Und da sieht man die obere geschweifte Klammer,
ab dem Zeitpunkt ist nämlich kurz vor dem roten Kreis,
da gibt es
nur zwei Boxen
Grüne Box und weiße Box. Das heißt,
diese Formel wird erfüllt ab der grünen Box.
Davor gibt es nämlich durchaus drei runde Sachen. Also da
gilt das noch nicht. Aber irgendwann in der Zukunft gilt
es. Und was haben wir noch? Da drunter,
blau oder braun an Till, nicht rund an Till Roth.
Okay, nicht rund an Till Roth, das wissen wir.
Das gilt ab da ab der grünen Box.
Das gilt also ab der grünen Box und davor
gilt blau oder braun
Ja, wenn wir diese Farben da mal als einen blauen,
braunen deuten, dann ist das braun, blau,
braun, blau.
Das gilt also die ganze Zeit bis zu diesem Zeitpunkt,
wo nicht rund an Tilruth gibt.
Leberwurst und Flieh, da könnte ich vermutlich auch sagen.
Gut. Was haben wir noch in der Zukunft?
Irgendwann gilt einmal rot, Antil, Grün, Antil Weiß.
Also rot weiß ich schon mal, wo das liegt,
da gibt es nämlich nur einen.
Jetzt wollen wir gucken,
Grün an Till Weiß
Grün-Antil Weiß. Weiß kenne ich davon irgendwie.
Irgendwann in der Zukunft. Also nicht in dem Prefix,
würde ich mal sagen. Denn Weiß gilt er ja,
aber so lange gilt nicht grün. Also das muss ja
irgendwann erfüllt sein. Aber in dem Prefix sehe ich das nicht.
Naja, und so entsprechend für diese weiteren Formeln.
Wir wissen jetzt also, was wir haben wollen.
Und jetzt müssen wir beim nächsten Mal sagen, okay,
wir wissen, was wir wollen.
Jetzt packen wir noch viel Symbolik dazu und sagen,
okay, diese Mantik identifizieren wir. Das heißt,
für alle möglichen Folgen gucken wir uns jetzt mal an,
wann gilt eine LTL-Formel.
Und das, wie gesagt, nächste Woche.
Bis dann