3 - Harte/weiche Synchronisation [ID:24346]
237 von 237 angezeigt

Moin Moin liebe Leute, weiter geht es im Kapitel Synchronisation von Unterbrechungen für die

Vorlesungsbetriebssysteme. In diesem Teil wollen wir uns kümmern um harte und weiche Synchronisation.

Fangen wir mit der harten Synchronisation an. Hat man im Prinzip auch schon ein paar

Mal jetzt nur noch sozusagen in das Konzept der Prioritätenebenen Modells eingepasst.

Also stellt euch vor, hier habt ihr diese typischen Produce-Consumengeschichten und wir

legen jetzt, das ist die Idee, den Buffer auf die in diesem Falle Ebene 1. Heißt, wir können

aus Ebene 1 heraus von der Produce-Methode aus direkt auf den Buffer zugreifen. Ist kein

Problem, weil ist in der Ebene. Aus der Ebene E0 können wir jetzt nicht direkt drauf zugreifen.

Wir müssen erst mit Kli die Interrupts ausschalten, damit wir auf der gleichen Ebene sind. Dann

dürfen wir zugreifen und mit die verlassen wir die Ebene wieder. Warum dürfen wir in

der Ebene E1 einfach drauf zugreifen? Wenn wir dann in der Ebene E1 sind, sowohl vom

Hauptprogramm aus, als auch vom Interrupt aus, dann wissen wir, Kontrollflüsse in

der Ebene E1 werden sequentialisiert. Heißt, erstmal läuft das Konsum komplett durch und

erst wenn das fertig ist, dann läuft das Produce komplett durch. Wenn beides komplett durch

läuft, ist irgendwie logisch. Da vermischt sich nichts von den Zugriffen, dann kann auch

nichts passieren. Gut, Vorteil ist klar, Konsistenz ist sichergestellt und ich sag mal, das ist

für Doofe. Also ein Kli und ein Sti außen rum zu schreiben, das kann jeder. Und das

werden wir noch sehen, das ist letztendlich auch unabhängig davon, was jetzt unser Compiler

aus unserem Code macht. Wir werden sehen, das ist nicht immer so. Also Idee einfach,

Kli Sti, oben den Zugriff außen rum. Dann kann man den Zustand auf die untere Ebene

legen, die höchstpriore Ebene, dann funktioniert die Sache. Jetzt kommt das große Aber. Das

große Aber lautet, erstens haben wir eine Breitbankwirkung, was soll das heißen? Heißt,

ich schalte ja alle Interrupts aus. Und zwar nicht nur, wie jetzt hier in unserem Beispiel

immer, den Tastatur Interrupt, der jetzt vielleicht was in diesen Buffer reinlegen will oder

davon rausnehmen will, sondern wir schalten ja auch die Interrupts von der Festplatte,

die Interrupts von der Ethernet-Karte und so weiter aus. Die wir ja eigentlich nun überhaupt

nicht ausschalten müssten, die stören uns an der Stelle ja überhaupt nicht. Nächster

Nachteil, Prioritätsverletzung. Ja, dadurch, dass wir mit unserem Hauptprogramm auf die

E1-Ebene wechseln, erhöhen wir sozusagen die Priorität von unserem Anwendungsprogramm.

Und dadurch werden gegebenenfalls ja wichtigere Sachen, nämlich andere Interrupts, gegebenenfalls

verzögert. Das will man eigentlich nicht. Ja, und das letzte, man kann das als prophylaktisches

Verfahren bezeichnen im folgenden Sinne. Gerade jetzt Tastatur Interrupt ist ein gutes Beispiel.

Wie viele Tasten kann man dann, sagen wir mal, pro Sekunde tippen? Aber ich weiß nicht,

wie schnell ihr tippt. Also ich würde sagen, ich schaffe so 1, 2, 3, 4 vielleicht Tasten

drücke pro Sekunde. Andersherum gefragt, wie oft könnte die CPU aus dem Tastatur-Buffer

abholen pro Sekunde? Ja, wahrscheinlich ein paar Millionen Mal. Das heißt, ich würde,

also ich blockiere die Interrupts, obwohl ich eigentlich nur vielleicht jedes millionstelmal

durch einen Interrupt unterbrochen werden würde. Also 99,9999% oder so trifft mich ja gar keine

Unterbrechung. Und trotzdem schalte ich die Interbrechung aus. Das ist eigentlich doof.

Jo, nutzt man das jetzt, das Verfahren oder nutzt man das jetzt besser nicht? Gut, das ist

natürlich immer die Frage, was sind die Vorteile, was sind die Nachteile? Die Vorteile,

dass man das Stroh doof anwenden kann, das ist toll. Nachteile ist jetzt die Frage,

wie schwerwiegend sind diese Nachteile? Ich brauche ja sagen, so eine Breitbandwirkung ist mir

doch wurscht, geht. Das ist mir das wichtigste. Ja, aber da gibt es ein Kriterium, dass man immer

im Hinterkopf haben müsste und das ist letztendlich die maximale Dauer, wie oft, wie lange verzögere

ich Interrupts. Es kann ja sein, stellt euch vor, was weiß ich, die Uhr tickt und die Uhr tickt und

die Uhr tickt. Die Ticks, die möchte ich mitkriegen, wenn ich jetzt aber über eine Länge bedauer,

die Interrupts ausschalte, dann kriege ich vielleicht mehrere Uhr und Ticks nicht mit.

Heißt letztendlich, meine Uhr geht falsch. Okay, dass die Uhr falsch geht, ist vielleicht nicht so

schlimm, aber wenn ich irgend so ein, na, von meinem Hammer, aber ein schöner Beispiel, wenn das Atomkraftwerk

sagt, mir wird warm und so ein Ding kriege ich nicht mit, das wäre eine dumme Idee. Also, was man

machen muss, ist abschätzen, ja wie lang sind die Interrupts maximal ausgeschaltet. Und das ist

sozusagen das Kriterium auf der einen Seite und auf der anderen Seite, ja wie oft kommen dann jetzt

von externen Interrupts, die dann eben potenziell verloren gehen können. Jetzt, wenn wir uns das

angucken für unser Beispiel, Zeichen in den Tastaturprofer legen bzw. da wieder rausholen,

ja was ist da die maximale Verzögerungsdauer? Ja, nicht viel, also das sind eine handvoll

Assembler Instruktionen, die reichen schon, um was in meinen Buffer reinzulegen bzw. da wieder

rauszuholen. Eine handvoll Assembler Instruktionen, da reden wir über ein paar Nanosekunden vielleicht,

das wäre sicherlich okay, jedenfalls in den allermeisten Fällen, Spezialfälle ist das

vielleicht auch schon zu lang. Also so ein bounded Buffer, das ist so ein Beispiel, da kann man sagen,

das könnte man mit cleave uns die regeln. Wir verzögern die Interrupts maximal nur ganz,

ganz, ganz, ganz wenig und das tolerieren wir. Anders wäre das, wenn wir jetzt nicht so eine

einfache Datenstruktur wie so einen bounded Buffer hätten, sondern keine Ahnung, irgendwas

Komplexeres, irgend so einen balancierten Baum, den wir vielleicht nach dem Einfügen eines Objekts

dann irgendwie noch umstrukturieren müssten. Wenn das dauert dann gegebenenfalls schon länger,

ja und dann muss man sagen, dann ist diese harte Synchronisation mit cleaves die nicht geeignet.

Das darf man dann einfach nicht benutzen. Jo, die Frage ist, was machen wir dann? Und da ist

der andere Ansatz die weiche Synchronisation. Gucken wir uns mal an, was damit gemeint ist und

gucken wir uns mal an, wie gut das dann wäre. Also die Idee ist jetzt, wir haben unseren Zustand

nicht mehr auf Ebene 1, sondern auf Ebene 0. Heißt, das Konsum braucht jetzt nichts mehr

besonderes tun, weil es ist in der gleichen Ebene, darf entsprechend auf die Daten zugreifen,

lesenschreibend. Aber jetzt sind wir mit unserer Produce Methode in der falschen Ebene. Die läuft

ja in der Intrapt Kontext ab und die Methode, die muss jetzt aufpassen, sie unterbricht das

Konsum ja theoretisch an einer beliebigen Stelle und muss jetzt aufpassen, dass es das Konsum nicht

durcheinander bringt beim Auslesen des Buffers. Und das ist jetzt die große Kunst, man schreibe

eine Consume bzw. eine Produce Methode, die so sind, dass das Konsum jederzeit durch das Produce

unterbrochen werden kann und beide Methoden laufen ein und frei durch. Wer gerade nichts zu tun hat,

der kann sich ja mal überlegen, ob er das schafft, diese zwei Methoden so zu schreiben. Das ist alles

andere als trivial, werden wir gleich sehen. Wir brauchen zwei Annahmen, die kennen wir schon.

Das Produce ist die Interrupt Funktion, das heißt, die unterbricht das Konsum, nicht umgekehrt,

alle anderen Kombinationen kommen nicht vor. Das Produce ist eine Interrupt Funktion, die hat also

von der Semantik her diese Rantokomplition Variante. Also das Produce wird immer durchlaufen,

von Anfang bis Ende, es kann das Konsum an beliebiger Stelle unterbrechen. Was wir jetzt

haben wollen, das werden wir noch merken, ist, das soll nachdem die beiden abgelaufen sind,

soll es so aussehen, als wenn entweder das Konsum komplett abgelaufen wäre, bevor das

Produce losgelaufen wäre. Oder umgekehrt, das Konsum läuft erst los, nachdem das Produce fertig

ist. Das ist eigentlich nicht so, das Konsum wird unterbrochen, irgendwo zwischenzeitlich,

aber es sieht aus Sicht des Anwendungsprogramms so aus, als wäre das Konsum erst nach dem Produce

losgelaufen. Der Effekt ist der gleiche. Ja, die Frage, wie kriegen wir das hin? Wir haben

nichts bei denken, das Beispiel hatten wir schon mal. Da haben wir gesehen, das hat nicht funktioniert.

Also woran lag das? Ja, das lag daran, dass wir hier dieses Occupied hatten, also die Anzahl

der in dem Buffer befindlichen Elemente, dass das eine Variable war, die an zwei Stellen geschrieben

wurde. Warum war das ein Problem? Ja, das Problem war, das Konsum hat irgendwie angefangen,

dann wurde es unterbrochen durch das Produce. Das Produce hat das Occupied geschrieben und das

Konsum ist dann weiter gelaufen und hat den vorher geänderten Wert einfach überschrieben und hat

damit die Änderung von Produce kaputt gemacht. Also da sieht man, wenn man Variablen hat, die von

zwei Seiten, von dem Produce und dem Konsum geschrieben wird, dann funktioniert es definitiv nicht.

Ja, jetzt kann man nachdenken, wie kann man das umbauen, dass dieses Problem nicht mehr auftritt.

Also im ersten Augenblick sieht es ja doch so aus, als bräuchten wir die Anzahl der Elemente in dem

Buffer. Wir brauchen es ja hier oben, um zu gucken, ob der Buffer schon voll ist, bzw. beim Konsum

brauchen wir diese Occupied, diesen Wert, um zu gucken, ob überhaupt was in dem Buffer drin ist.

Ja, das kann man aber im Intel anders machen, nämlich folgendermaßen, wir lassen das Occupied

einfach weg. Wir haben nur noch unsere zwei Schreiblesezeiger und aus den Schreiblesezeigern

heraus kann man auch ermitteln, ob noch Platz im Buffer ist, bzw. ob noch Elemente in dem Buffer

sind. Ja, und dann sieht es etwa folgendermaßen aus, ich gucke beim Produce, ob ich noch Platz

habe, wenn kann ich meinen Next-In-Zeiger um eins verschieben und ich treffe noch nicht auf die

auszulesenden Bites, dann könnte ich weitermachen, dann ist okay. Oder umgekehrt, wenn der Next-Out-Zeiger

dahin zeigt, wo der Next-In-Zeiger hin zeigt, das heißt da ist Next im Buffer und dann würde das

Konsum zurückkehren. Anhand dieser zwei Zeiger kann ich sehen, ob noch was im Buffer drin ist,

bzw. wie viel noch drin ist. Jo, was hilft mir das jetzt? Jetzt habe ich das Occupied weg.

Nichtsdestotrotz sind ja jetzt noch Variablen drin, also beispielsweise das Next-Out hier oben,

was von dem Produce gelesen wird, von dem Konsum geschrieben. Da muss man sich ja auch Gedanken

machen, ist das okay. Next-In wird hier oben geschrieben, Next-In wird hier beim Konsum gelesen.

Okay, aber es sollte jetzt jedem klar sein, das sind die Stellen, wo es kritisch ist. Wenn ich

hier das Next-Out lese, kann ich dann in irgendeinen inkonsistenten Zustand kommen, weil ich hier

irgendwas kaputtes lese. Oder hier unten bei dem Next-In oder wenn ich jetzt hier das Next-Out schreibe,

kann es sein, dass ich da mit dem Leser hier oben durcheinander bringe. Und das müsste man

sich jetzt im Detail angucken. Jo, wie machen wir das? Man muss jetzt gucken, von der Idee her,

das Konsum kann ja unterbrochen werden. Es kann vor dem If unterbrochen werden, es kann während

der Bedingungsberechnung hier unterbrochen werden, es kann vor dem Return unterbrochen werden,

es kann vor dem Anlegen der Variablen unterbrochen werden, usw. usw. Da muss man sich jetzt immer

überlegen, was ist dann jetzt, sagen wir mal, es wird noch vor dem If unterbrochen durch das

Produce. Ja, dann sollte jedem klar sein, das sieht dann so aus, als wäre das Produce erst

mal abgelaufen und dann fängt das Konsum ja erst richtig an. Das würde sicherlich funktionieren.

Wenn ich jetzt vor dem Lesen von dem Next-In unterbrochen werde, also ich habe das If angefangen,

ich habe das Next-Out schon gelesen und jetzt läuft das Produce. Das Next-In habe ich noch nicht,

wichtig. Jetzt läuft das Produce los. Ja, dann würde das Produce das Next-In ändern, bevor ich

das lese. Heißt, es sieht für mich so aus, als würde das Konsum nach dem Durchlauf vom Produce

erst starten. Es hat eigentlich schon früher angefangen, aber es hat ja noch keinen Effekt von

dem Produce gesehen. Erst wenn es das Next-In gelesen hat, merkt es die Auswirkungen von dem

Produce. Wenn es vorher unterbrochen wird, dann hat die halt noch nicht gemerkt. Heißt,

das Produce ist sozusagen komplett vorher durchgelaufen. Das ist die eine Variante. Hier

ersten Schritt. Ich gucke, was passiert, wenn ich das Next-In noch nicht gelesen habe. Eine andere

Variante wäre, es könnte ja sein, ich habe das Next-In schon gelesen und werde jetzt unterbrochen.

Wie schaut das jetzt aus? Ja, ich habe das Next-In schon gelesen und alles, was ich dann tue,

hat ja keine, da hat das Produce keine Auswirkungen mehr drauf. Das heißt, es sieht so aus, als würde

das Konsum komplett durchlaufen und wäre von dem Produce gar nicht geändert worden, gar nicht

beeinflusst gewesen. Heißt, das wäre der Fall. Es sieht so aus, aus der Sicht der Anwendung,

als ob das Konsum schon komplett durchgelaufen wäre, bevor das Produce überhaupt aufgerufen

worden wäre. Also, die zwei Fälle vor und nach dem Next-In wäre okay. Da wäre Unterbrechung kein

Problem. Jetzt haben wir hier noch die Änderung von dem Next-Out. Wie schaut das da aus? Also,

das mit dem vor dem Next-Out haben wir uns im Prinzip schon angeguckt. Das sähe dann so aus,

als wäre das Produce vor dem Konsum abgelaufen. Es war ja nach dem Next-In. So, wie wäre das jetzt,

wenn wir hier das Next-Out schon geschrieben hätten? Ja, das heißt ja praktisch, das Konsum wäre

schon komplett durch gewesen, bevor das Produce angelaufen gewesen wäre. Heißt, auch der Fall

wäre okay. Also, dann haben wir unsere vier Fälle, die wir hier überprüfen müssen. Vor dem Next-In,

nach dem Next-In, vor dem Next-Out, nach dem Next-Out. Und da sieht man, die Konsistenzbedingungen

ist in diesem Falle immer erfüllt, egal wann das Produce das Konsum unterbricht. Anderes Beispiel

dazu. Also, wie könnte man solche Probleme noch lösen? Gehen wir mal zurück zu unserem Zeitleseproblem.

Ihr erinnert euch, wir haben eine globale Variable, die wird vom Timer Tick jeweils

inkrementiert und wir haben eine Time-Funktion, die liest einfach diese globale Variable aus.

Allerdings, wir sind sagen wir mal nur auf einer 16-Bit-Architektur und wir lesen eine 32-Bit-Variable.

Ja, dann müssen wir das in zwei Häppchen machen. Und da haben wir uns mal angeguckt,

dass es halt doof, wenn wir den ersten Teil der Uhrzeit gelesen haben, dann unterbrochen werden

und dann erst den zweiten Teil lesen. Und das war das Problem, dass die Daten nicht automat

gelesen wurden. Gut, Lösungsidee wäre, wir lesen die Daten einfach und gehen davon aus,

dass wir nicht unterbrochen werden. Aber wir testen, ob wir unterbrochen wurden und wenn ja,

dann machen wir es halt noch einmal. Was können wir jetzt wieder als Annahmen treffen? Na so ähnlich

wie gerade eben. Wir sagen, die Time-Funktion, die wird vom Hauptprogramm aus aufgerufen,

das heißt, die kann unterbrochen werden durch den Timer Tick, umgekehrt nicht. Und weil der

Timerhändler eine Interrupt-Funktion ist, läuft die immer durch mit Ranto-Completion. Ja, und auch

jetzt, so wie gerade eben, müssen wir es irgendwie hinkriegen, dass es nach außen hin so aussieht,

als wenn die Time-Funktion vor Timerhändler, vor dem Tick ausgeführt worden wäre oder danach.

Also nicht während sozusagen, sondern vorher oder hinterher. Folgende Idee, wie kriegen wir raus,

ob wir unterbrochen worden sind? Ja, wir setzen einfach ein Interrupted-Flag auf Fault. Wir lesen

die Zeit und danach gucken wir dieses Interrupted-Flag an und wenn das in der Zwischenzeit auf 1

gesetzt wurde, dann ist in der Zwischenzeit der Timerhändler gelaufen. Seht ihr hier,

der Timerhändler, der zählt jetzt nicht nur die Zeit hoch, sondern der zeigt auch noch an,

dass er gegebenenfalls eine Funktion unterbrochen hat. Das stimmt jetzt nicht ganz perfekt. Ihr

könnt euch vorstellen, ich habe hier das Interrupted-Flag gerade auf Fault gesetzt,

werde dann unterbrochen, dann wird das Interrupted schon wieder gesetzt und die Zeit würde

incrementiert und danach würde ich die Zeit lesen. Das Zeitlesen wäre dann gar nicht unterbrochen,

aber trotz allem würde ich diesen Vorgang wiederholen. Genauso könnte es sein,

ich hätte die Zeit schon komplett gelesen, wäre eigentlich schon komplett fertig. Wenn

dann der Timerhändler läuft, dann setzt er mir dieses Interrupted-Flag trotzdem noch und ich

wiederhole mein eigentlich gutes Lesen noch einmal. Macht aber im Prinzip nichts, ich kriege auf jeden

Fall, wenn es einmal richtig durchläuft, einen konsistenten Zustand meiner Uhrzeit. Das ist

natürlich das, das wollen wir eigentlich. Jo, gucken wir uns mal an, welche Vor- und welche

Nachteile haben wir jetzt mit der Weichensynchronisation. Vorteil ist auch hier,

Konsistenz ist sehr geschält. Das funktioniert, so man es dann richtig macht. Zweiter Vorteil,

Priorität wird nie verletzt. Warum nicht? Die Interrupts, also die Abläufe im Rechner,

die höhere Priorität haben, die dürfen jederzeit laufen. Ihr habt gerade beim Timer Beispiel gesehen,

der Interrupt ist nie blockiert, er darf jederzeit kommen. Gut und in den meisten Fällen,

hatten wir ja auch beim Tastatur Interrupt, da haben wir gesagt, in allerallermeisten Fällen

werden wir ja gar nicht unterbrochen. Genauso hier beim Timer Tick, typischerweise werden wir

nicht unterbrochen. Dass die Uhrzeit genau in dem Moment tickt, wo wir sie abfragen,

habe ich gehabt, aber nur sehr selten. Und wenn wir nicht unterbrochen werden, dann kostet es ja

auch natürlich nichts. Eventuell kostet es gar nichts, im Beispiel Bound Buffer, die Produce

Funktion, die konnte einfach immer kostenlos durchlaufen und das Konsum genauso. Das ist

sozusagen der Best Case überhaupt. Und beim Timer auslesen haben wir gesehen, ja eigentlich

kostet es uns nichts. Es kostet eventuell was, wenn wir doch mal unterbrochen worden sind,

dann müssen wir es halt nochmal machen. Und ja, es kostet uns natürlich hier ein Mini-Ticklchen,

dieses Interrupted Flag auf 1 zu setzen, bzw. hier auf 0 zu setzen und abzufragen. Also ganz

kostenlos ist es nicht, aber ihr könnt euch vorstellen, das ist natürlich Mini-Minimal.

Ja, jetzt kommen wir allerdings leider zu den Nachteilen und die sind wieder groß. Also ein

großer Nachteil ist, dass die Lösung nicht trivial ist. Also ich weiß nicht, wer sich mal

hingesetzt hat und versucht hat, dieses Bound Buffer Problem mal selber zu lösen und ich weiß nicht,

wie viele Leute von denen, die es versucht haben, auf eine Lösung zu, wie viele Leute dann geschafft

haben, auch eine Lösung zu kommen. Das ist nicht einfach. Selbst wenn man mal in der Literatur sich

so eine Lösung anguckt, wenn man schon lange eventuell darüber nachdenkt, überhaupt zu verstehen,

warum die funktioniert und es dauert noch noch viel, viel länger, die gegebenenfalls auch noch

zu verifizieren diese Lösung. Also kann es in unter keinen Umständen passieren, dass da irgendwie

Interrupts verloren gehen, Buffer in inkonsistenten Zustand kommen und so weiter. Und jetzt noch das

größte Problem, das ist compilerabhängig das Problem. Ihr könnt euch vorstellen, ich gehe

noch mal zurück zu dem Beispiel hier. So habe ich es vielleicht in C oder C++ hingeschrieben,

aber das kann mir rein theoretisch passieren, dass ein compiler Sachen umsortiert, weil er der Meinung

ist, in anderer Reihenfolge werden die Instruktionen schneller ausgeführt. Dann könnte man denken,

dann kann er diese zwei Instruktionen hier vertauschen. Okay, in diesem Falle schlechtes

Beispiel, aber in diesem Falle darf er nicht, weil der Rollenteil steht. Aber ihr könnt euch beim

Bounded Buffer vorstellen, wenn er da Zeilen vertauscht, gänzlich oder nur vielleicht einzelne

Assembler Instruktionen von diesen Instruktionen, dann funktionieren die Lösungen eventuell schon

gar nicht mehr. Also man darf bei diesen Lösungen häufig gar nicht die C Variante oder C++ Variante

oder so angucken, sondern man muss den generierten Code angucken und gucken, ob der die Konsistenzgarantie

nicht zerstört. Das ist natürlich eine ganz hässliche Baustelle. Ich habe mein Betriebssystem

geschrieben, alles funktioniert wunderbar, ich habe verifiziert, super. Und dann kommt eine neue

compiler Variante raus und nichts geht mehr. Dann kann ich mein Code neu schreiben, das kann es

auch wenig sein. Ein letzter Punkt, der ist nicht ganz so schlimm, aber manchmal kneift es

ggf. auch. Wenn ich nur meine Zeit schnell auslese und das wiederholen muss im Falle,

dass mich ein Interrupt getroffen hat, dann ist das nicht so schlimm. Wenn ich aber, was weiß ich,

ein halbes Megabyte Daten ausgelesen habe, das kostet mich ggf. eine ganze Weile und merke dann,

oh in der Zwischenzeit bin ich unterbrochen worden, dann muss ich das halbe Megabyte noch

mal lesen. Das kneift mich eventuell dann. Also das geht eigentlich jetzt, diese weiche Synchronisation

geht nur für kleine Datenmengen typischerweise. Jo, kleines Fazit, weiche Synchronisation an sich

ist das klasse. Ich habe es gesehen an dem Baunet Buffer Beispiel, das Produce kann durchlaufen,

wird nicht beeinflusst vom Konsum und das Konsum kann durchlaufen, wird nicht beeinflusst durch

das Produce. Beide Funktionen können jederzeit ohne Beeinträchtigung der anderen durchlaufen. Super.

Muss man allerdings für jedes Problem, was man hat, jedes Mal eine neue Lösung sich ausdenken.

Es gibt keine Lösung, die allgemeingültig und immer funktioniert. Jo, und dementsprechend ist

das nicht, wenn es nicht allgemeingültig ist, ist es natürlich mühsam anzuwenden. Wenn ich eine

verkettete Liste habe, muss ich es komplett anders machen als bei einem Baunet Buffer, muss

ich es komplett anders machen als bei einem balancierten Baum, muss ich es komplett anders

machen für und so weiter und so weiter. Und sich jedes Mal eine neue Lösung auszudenken für jedes

neue Problem, was ich habe, jedes Mal verifizieren und jedes Mal verifizieren, wenn ich den Compiler

ändere, das kneift mich, das mag ich eigentlich nicht. Jo, ihr seht harte Synchronisation, weiche

Synchronisation, beide haben ihre gravierenden Nachteile, gravierenden Vorteile. Wir werden uns

im nächsten Video jetzt noch eine andere Lösung angucken, die ist in den meisten Fällen Mittel

der Wahl. Das ist so eine Art Kompromiss zwischen den beiden.

Teil einer Videoserie :
Teil eines Kapitels:
Unterbrechungen, Synchronisation

Zugänglich über

Offener Zugang

Dauer

00:27:37 Min

Aufnahmedatum

2020-11-18

Hochgeladen am

2020-11-19 12:18:07

Sprache

de-DE

6. Kapitel der Vorlesung Betriebssysteme.

Folien zum Video.

Tags

betriebssysteme operating systems
Einbetten
Wordpress FAU Plugin
iFrame
Teilen